1 line
7.0 MiB
Plaintext
1 line
7.0 MiB
Plaintext
{"repo": "astrajwt/obsidian-paper-daily", "files": {"main.js": {"529169e487e830baba6a54c300bff00e0709d1e3": {"t": 1785746574.473212, "n": 233554, "h": "3eefb2efdb38ed80", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nfunction fmtTokens(n) {\n if (n >= 1e6)\n return `${(n / 1e6).toFixed(1)}m`;\n if (n >= 1e3)\n return `${(n / 1e3).toFixed(1)}k`;\n return String(n);\n}\nvar BASE = 24;\nvar STEP = 160;\nvar usedSlots = /* @__PURE__ */ new Set();\nfunction acquireSlot() {\n let s = 0;\n while (usedSlots.has(s))\n s++;\n usedSlots.add(s);\n return s;\n}\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.slot = acquireSlot();\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n `bottom:${BASE + this.slot * STEP}px`,\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(`tokens: ${fmtTokens(total)}`);\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n usedSlots.delete(this.slot);\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\" });\n const fmt = (d) => d.toISOString().slice(0, 10);\n const today = new Date();\n const lastWeek = new Date(today);\n lastWeek.setDate(today.getDate() - 7);\n let startInput;\n let endInput;\n new import_obsidian6.Setting(contentEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").addText((text) => {\n startInput = text.inputEl;\n startInput.type = \"date\";\n startInput.value = fmt(lastWeek);\n });\n new import_obsidian6.Setting(contentEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").addText((text) => {\n endInput = text.inputEl;\n endInput.type = \"date\";\n endInput.value = fmt(today);\n });\n const errorEl = contentEl.createEl(\"p\");\n errorEl.style.cssText = \"color:var(--text-error);font-size:0.85em;margin:8px 0 0;min-height:1.2em;\";\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"\\u53D6\\u6D88\").onClick(() => this.close())).addButton((btn) => btn.setButtonText(\"\\u5F00\\u59CB\\u751F\\u6210\").setCta().onClick(() => {\n const start = startInput.value;\n const end = endInput.value;\n if (!start || !end) {\n errorEl.setText(\"\\u8BF7\\u9009\\u62E9\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n if (start > end) {\n errorEl.setText(\"\\u5F00\\u59CB\\u65E5\\u671F\\u4E0D\\u80FD\\u665A\\u4E8E\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n this.close();\n void this.plugin.runBackfillWithUI(start, end);\n }));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "290e06c26975312c1d72c7b205a3dfa3ac31346d": {"t": 1785765873.8832402, "n": 233554, "h": "3eefb2efdb38ed80", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nfunction fmtTokens(n) {\n if (n >= 1e6)\n return `${(n / 1e6).toFixed(1)}m`;\n if (n >= 1e3)\n return `${(n / 1e3).toFixed(1)}k`;\n return String(n);\n}\nvar BASE = 24;\nvar STEP = 160;\nvar usedSlots = /* @__PURE__ */ new Set();\nfunction acquireSlot() {\n let s = 0;\n while (usedSlots.has(s))\n s++;\n usedSlots.add(s);\n return s;\n}\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.slot = acquireSlot();\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n `bottom:${BASE + this.slot * STEP}px`,\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(`tokens: ${fmtTokens(total)}`);\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n usedSlots.delete(this.slot);\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\" });\n const fmt = (d) => d.toISOString().slice(0, 10);\n const today = new Date();\n const lastWeek = new Date(today);\n lastWeek.setDate(today.getDate() - 7);\n let startInput;\n let endInput;\n new import_obsidian6.Setting(contentEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").addText((text) => {\n startInput = text.inputEl;\n startInput.type = \"date\";\n startInput.value = fmt(lastWeek);\n });\n new import_obsidian6.Setting(contentEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").addText((text) => {\n endInput = text.inputEl;\n endInput.type = \"date\";\n endInput.value = fmt(today);\n });\n const errorEl = contentEl.createEl(\"p\");\n errorEl.style.cssText = \"color:var(--text-error);font-size:0.85em;margin:8px 0 0;min-height:1.2em;\";\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"\\u53D6\\u6D88\").onClick(() => this.close())).addButton((btn) => btn.setButtonText(\"\\u5F00\\u59CB\\u751F\\u6210\").setCta().onClick(() => {\n const start = startInput.value;\n const end = endInput.value;\n if (!start || !end) {\n errorEl.setText(\"\\u8BF7\\u9009\\u62E9\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n if (start > end) {\n errorEl.setText(\"\\u5F00\\u59CB\\u65E5\\u671F\\u4E0D\\u80FD\\u665A\\u4E8E\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n this.close();\n void this.plugin.runBackfillWithUI(start, end);\n }));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "9a2a4aeeca646f25f88bf1e83816f0a8a06cd6ef": {"t": 1785765876.5308213, "n": 233340, "h": "1e6c7a1037b62032", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nfunction fmtTokens(n) {\n if (n >= 1e6)\n return `${(n / 1e6).toFixed(1)}m`;\n if (n >= 1e3)\n return `${(n / 1e3).toFixed(1)}k`;\n return String(n);\n}\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\", side = \"right\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n side === \"left\" ? \"left:24px\" : \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(`tokens: ${fmtTokens(total)}`);\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\", \"left\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\" });\n const fmt = (d) => d.toISOString().slice(0, 10);\n const today = new Date();\n const lastWeek = new Date(today);\n lastWeek.setDate(today.getDate() - 7);\n let startInput;\n let endInput;\n new import_obsidian6.Setting(contentEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").addText((text) => {\n startInput = text.inputEl;\n startInput.type = \"date\";\n startInput.value = fmt(lastWeek);\n });\n new import_obsidian6.Setting(contentEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").addText((text) => {\n endInput = text.inputEl;\n endInput.type = \"date\";\n endInput.value = fmt(today);\n });\n const errorEl = contentEl.createEl(\"p\");\n errorEl.style.cssText = \"color:var(--text-error);font-size:0.85em;margin:8px 0 0;min-height:1.2em;\";\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"\\u53D6\\u6D88\").onClick(() => this.close())).addButton((btn) => btn.setButtonText(\"\\u5F00\\u59CB\\u751F\\u6210\").setCta().onClick(() => {\n const start = startInput.value;\n const end = endInput.value;\n if (!start || !end) {\n errorEl.setText(\"\\u8BF7\\u9009\\u62E9\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n if (start > end) {\n errorEl.setText(\"\\u5F00\\u59CB\\u65E5\\u671F\\u4E0D\\u80FD\\u665A\\u4E8E\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n this.close();\n void this.plugin.runBackfillWithUI(start, end);\n }));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "462b965bd305cf38ce897396e62d6d72805bc0b2": {"t": 1785765878.8005817, "n": 233284, "h": "1d085cd13e7e74ba", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nfunction fmtTokens(n) {\n if (n >= 1e6)\n return `${(n / 1e6).toFixed(1)}m`;\n if (n >= 1e3)\n return `${(n / 1e3).toFixed(1)}k`;\n return String(n);\n}\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(`tokens: ${fmtTokens(total)}`);\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\" });\n const fmt = (d) => d.toISOString().slice(0, 10);\n const today = new Date();\n const lastWeek = new Date(today);\n lastWeek.setDate(today.getDate() - 7);\n let startInput;\n let endInput;\n new import_obsidian6.Setting(contentEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").addText((text) => {\n startInput = text.inputEl;\n startInput.type = \"date\";\n startInput.value = fmt(lastWeek);\n });\n new import_obsidian6.Setting(contentEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").addText((text) => {\n endInput = text.inputEl;\n endInput.type = \"date\";\n endInput.value = fmt(today);\n });\n const errorEl = contentEl.createEl(\"p\");\n errorEl.style.cssText = \"color:var(--text-error);font-size:0.85em;margin:8px 0 0;min-height:1.2em;\";\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"\\u53D6\\u6D88\").onClick(() => this.close())).addButton((btn) => btn.setButtonText(\"\\u5F00\\u59CB\\u751F\\u6210\").setCta().onClick(() => {\n const start = startInput.value;\n const end = endInput.value;\n if (!start || !end) {\n errorEl.setText(\"\\u8BF7\\u9009\\u62E9\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n if (start > end) {\n errorEl.setText(\"\\u5F00\\u59CB\\u65E5\\u671F\\u4E0D\\u80FD\\u665A\\u4E8E\\u7ED3\\u675F\\u65E5\\u671F\\u3002\");\n return;\n }\n this.close();\n void this.plugin.runBackfillWithUI(start, end);\n }));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "c9888197357a252038378bcb1b8a47e5afdac2a1": {"t": 1785765881.6109896, "n": 233009, "h": "d5cedb5ba6b1ccf0", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nfunction fmtTokens(n) {\n if (n >= 1e6)\n return `${(n / 1e6).toFixed(1)}m`;\n if (n >= 1e3)\n return `${(n / 1e3).toFixed(1)}k`;\n return String(n);\n}\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(`tokens: ${fmtTokens(total)}`);\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian6.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian6.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "46457b02267b81307c5610e51e25edf2a730a0fd": {"t": 1785765883.5772283, "n": 234029, "h": "e03064cd343cf09b", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_J = paper.categories) != null ? _J : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nfunction fmtTokens(n) {\n if (n >= 1e6)\n return `${(n / 1e6).toFixed(1)}m`;\n if (n >= 1e3)\n return `${(n / 1e3).toFixed(1)}k`;\n return String(n);\n}\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(`tokens: ${fmtTokens(total)}`);\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian6.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian6.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "75d9a63e4c278603ee569cabbe6ec1ffad1bd7f6": {"t": 1785765886.6496594, "n": 233967, "h": "5b5c4a8541a01307", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction abortRejection(signal) {\n return new Promise((_, reject) => {\n if (signal.aborted) {\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", () => reject(new DOMException(\"Aborted\", \"AbortError\")), { once: true });\n });\n}\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const fetchPromise = (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const response = input.signal ? await Promise.race([fetchPromise, abortRejection(input.signal)]) : await fetchPromise;\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n }, input.signal ? { signal: input.signal } : void 0);\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens, signal: options.signal });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens, signal: options.signal });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_J = paper.categories) != null ? _J : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(\n `Tokens: ${inputTokens.toLocaleString()} in + ${outputTokens.toLocaleString()} out = ${total.toLocaleString()}`\n );\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n fp.setMessage(\"\\u23F9 \\u6B63\\u5728\\u505C\\u6B62...\");\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian6.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian6.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "79f0b7f4e62ea08d248ead1b43a8f4ddfede0bf3": {"t": 1785765888.636446, "n": 233312, "h": "91e6806d2266e2f1", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n /**\n * Append content to a log file, then rotate if the file exceeds maxBytes.\n * When rotating, the oldest half is discarded so the file stays near maxBytes/2.\n * Uses character count as a byte approximation (safe for ASCII-heavy logs).\n */\n async appendLogWithRotation(filePath, content, maxBytes) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n let current = \"\";\n if (existing instanceof import_obsidian2.TFile) {\n current = await this.app.vault.read(existing);\n }\n let next = current + content;\n if (next.length > maxBytes) {\n const keepFrom = next.length - Math.floor(maxBytes / 2);\n const newlineIdx = next.indexOf(\"\\n\", keepFrom);\n const tail = newlineIdx !== -1 ? next.slice(newlineIdx + 1) : next.slice(keepFrom);\n const keptKB = Math.round(tail.length / 1024);\n next = `[LOG ROTATED ${new Date().toISOString()} \\u2014 older entries removed, kept last ~${keptKB}KB]\n` + tail;\n }\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, next);\n } else {\n await this.app.vault.create(normalized, next);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const SINGLE_CALL_TOKEN_WARN = 2e4;\n const TOTAL_TOKEN_WARN = 5e4;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n if (inputTokens > SINGLE_CALL_TOKEN_WARN) {\n log(`[WARN][TOKEN] ${label} single-call input=${inputTokens} exceeds threshold (${SINGLE_CALL_TOKEN_WARN}) \\u2014 check prompt size`);\n }\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`[ERROR][FETCH] url=${fetchUrl} error=${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`[ERROR][HF_FETCH] error=${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`[ERROR][SCORING] batch=${batchIdx + 1}/${totalBatches} error=${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`[ERROR][DEEP_READ_WRITE] paper=${i + 1}/${topN} id=${baseId} error=${String(writeErr)}`);\n }\n } catch (err) {\n log(`[ERROR][DEEP_READ] paper=${i + 1}/${topN} id=${baseId} error=${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`[ERROR][LLM] provider=${settings.llm.provider} model=${settings.llm.model} error=${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_J = paper.categories) != null ? _J : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`[ERROR][WRITE] path=${inboxPath} error=${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n if (totalInputTokens > 0) {\n log(`Token summary: totalInput=${totalInputTokens} totalOutput=${totalOutputTokens}`);\n if (totalInputTokens > TOTAL_TOKEN_WARN) {\n log(`[WARN][TOKEN] total run input=${totalInputTokens} exceeds ${TOTAL_TOKEN_WARN} \\u2014 consider reducing deepRead.topN or disabling deep read`);\n }\n }\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendLogWithRotation(logPath, logLines.join(\"\\n\") + \"\\n\", 10 * 1024 * 1024);\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(\n `Tokens: ${inputTokens.toLocaleString()} in + ${outputTokens.toLocaleString()} out = ${total.toLocaleString()}`\n );\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian6.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian6.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "5b5226b0a5715516f21b2f2568043059ac232e6e": {"t": 1785765891.029748, "n": 231282, "h": "de75a8979ab95dbc", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_J = paper.categories) != null ? _J : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(\n `Tokens: ${inputTokens.toLocaleString()} in + ${outputTokens.toLocaleString()} out = ${total.toLocaleString()}`\n );\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian6.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian6.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "346ca5fa8a12d39276be0d4cc1e8e78e7c443895": {"t": 1785765893.04594, "n": 231282, "h": "08d04a2f63496077", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian6 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n deepRead: {\n enabled: false,\n topN: 10,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u7CBE\\u8BFB\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF081\\u2013999\\uFF09| Number of top papers to deep-read per day (1\\u2013999, default 10)\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"10\").setValue(String((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 10)).onChange(async (value) => {\n const n = parseInt(value, 10);\n if (!isNaN(n) && n >= 1 && n <= 999) {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: n };\n await this.plugin.saveSettings();\n }\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian5 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian5.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: input.prompt }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, interestHotnessSection, error) {\n var _a2, _b, _c, _d;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const fnTemplate = ((_d = (_c = settings.deepRead) == null ? void 0 : _c.fileNameTemplate) == null ? void 0 : _d.trim()) || \"{{title}}-deep-read-{{model}}\";\n const deepReadPapers = rankedPapers.filter((p) => p.deepReadAnalysis);\n let featuredPapersSection = \"\";\n if (deepReadPapers.length > 0) {\n const featRows = deepReadPapers.map((p, i) => {\n var _a3;\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const hits = ((_a3 = p.interestHits) != null ? _a3 : []).slice(0, 3).join(\", \") || \"-\";\n const drLink = `[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`;\n return `| ${i + 1} | ${titleLink} | ${score} | ${hits} | ${drLink} |`;\n });\n featuredPapersSection = [\n `## \\u7CBE\\u9009\\u8BBA\\u6587 / Featured Papers (${deepReadPapers.length})`,\n \"\",\n \"> \\u4EE5\\u4E0B\\u8BBA\\u6587\\u5DF2\\u5B8C\\u6210\\u5168\\u6587\\u7CBE\\u8BFB\\uFF0C\\u70B9\\u51FB Deep Read \\u67E5\\u770B\\u8BE6\\u7EC6\\u5206\\u6790\\u3002\",\n \"\",\n \"| # | Title | Score | Hits | Deep Read |\",\n \"|---|-------|-------|------|-----------|\",\n ...featRows\n ].join(\"\\n\");\n }\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n if (featuredPapersSection)\n sections.push(\"\", featuredPapersSection);\n sections.push(\"\", digestSection);\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 10, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_J = paper.categories) != null ? _J : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(\n `Tokens: ${inputTokens.toLocaleString()} in + ${outputTokens.toLocaleString()} out = ${total.toLocaleString()}`\n );\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian6.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian6.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian6.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian6.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian6.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian6.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian6.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian6.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian6.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian6.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian6.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "77922232c802a78ddac8e08c414e77bb1a0e1f10": {"t": 1785765895.1072328, "n": 233521, "h": "c47976086f676bf8", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, interestHotnessSection, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2, _c, _d;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}\\\\|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fnTemplate = ((_b2 = (_a3 = settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) == null ? void 0 : _b2.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_c = p.llmSummary) != null ? _c : \"\");\n const hits = ((_d = p.interestHits) != null ? _d : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header];\n if (interestHotnessSection)\n sections.push(\"\", interestHotnessSection);\n sections.push(\"\", digestSection);\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n let interestHotnessSection = \"\";\n if (interestKeywords.length > 0) {\n const areaMap = /* @__PURE__ */ new Map();\n for (const kw of interestKeywords) {\n areaMap.set(kw.keyword, { keyword: kw.keyword, weight: kw.weight, count: 0, totalScore: 0, scored: 0 });\n }\n for (const paper of rankedPapers) {\n for (const hit of (_H = paper.interestHits) != null ? _H : []) {\n const s = areaMap.get(hit);\n if (s) {\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n if (!s.topPaper || paper.llmScore > ((_I = s.topPaper.llmScore) != null ? _I : 0))\n s.topPaper = paper;\n }\n }\n }\n }\n const hotAreas = [...areaMap.values()].filter((s) => s.count > 0).sort((a, b) => {\n const hotA = (a.scored > 0 ? a.totalScore / a.scored : 5) * Math.log1p(a.count) * a.weight;\n const hotB = (b.scored > 0 ? b.totalScore / b.scored : 5) * Math.log1p(b.count) * b.weight;\n return hotB - hotA;\n });\n if (hotAreas.length > 0) {\n const hasScores = hotAreas.some((s) => s.scored > 0);\n const rows = hotAreas.map((s) => {\n const avgScore = s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\";\n const top = s.topPaper;\n const topTitle = top ? top.links.html ? `[${escapeTableCell(top.title.slice(0, 45))}${top.title.length > 45 ? \"\\u2026\" : \"\"}](${top.links.html})` : escapeTableCell(top.title.slice(0, 45)) : \"-\";\n return hasScores ? `| ${s.keyword} | ${s.count} | ${avgScore} | ${topTitle} |` : `| ${s.keyword} | ${s.count} | ${topTitle} |`;\n });\n interestHotnessSection = [\n \"## \\u4ECA\\u65E5\\u5174\\u8DA3\\u9886\\u57DF\\u70ED\\u5EA6\",\n \"\",\n hasScores ? \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u5E73\\u5747\\u5206 | \\u4EE3\\u8868\\u8BBA\\u6587 |\" : \"| \\u5173\\u952E\\u8BCD | \\u547D\\u4E2D\\u8BBA\\u6587 | \\u4EE3\\u8868\\u8BBA\\u6587 |\",\n hasScores ? \"|--------|---------|--------|---------|\" : \"|--------|---------|---------|\",\n ...rows\n ].join(\"\\n\");\n }\n }\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_J = paper.categories) != null ? _J : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, interestHotnessSection, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(\n `Tokens: ${inputTokens.toLocaleString()} in + ${outputTokens.toLocaleString()} out = ${total.toLocaleString()}`\n );\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "f2995f076b2694888fb974d8f8ac0ae24b7e1a8b": {"t": 1785765897.239532, "n": 231184, "h": "7f9b72d88627526c", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2, _c, _d;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}\\\\|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fnTemplate = ((_b2 = (_a3 = settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) == null ? void 0 : _b2.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_c = p.llmSummary) != null ? _c : \"\");\n const hits = ((_d = p.interestHits) != null ? _d : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n var _a3;\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n (_a3 = options.onTokenUpdate) == null ? void 0 : _a3.call(options, totalInputTokens, totalOutputTokens);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_H = paper.categories) != null ? _H : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n this.tokenEl = this.el.createEl(\"div\");\n this.tokenEl.style.cssText = [\n \"font-size:0.78em\",\n \"color:var(--text-faint)\",\n \"margin-top:6px\",\n \"display:none\"\n ].join(\";\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n setTokens(inputTokens, outputTokens) {\n const total = inputTokens + outputTokens;\n this.tokenEl.setText(\n `Tokens: ${inputTokens.toLocaleString()} in + ${outputTokens.toLocaleString()} out = ${total.toLocaleString()}`\n );\n this.tokenEl.style.display = \"\";\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal, onTokenUpdate) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal, onTokenUpdate }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal, (i, o) => fp.setTokens(i, o));\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "105f23c69d2fbf9d925a6e732be7c988164b2cda": {"t": 1785765901.7447433, "n": 230523, "h": "da70b16ccc525471", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2, _c, _d;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}\\\\|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fnTemplate = ((_b2 = (_a3 = settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) == null ? void 0 : _b2.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}\\\\|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_c = p.llmSummary) != null ? _c : \"\");\n const hits = ((_d = p.interestHits) != null ? _d : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_H = paper.categories) != null ? _H : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "7436e0c1fb09efe4bbcda6356368ec4cd4151b7b": {"t": 1785765903.6417396, "n": 230519, "h": "789b640f79677714", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6587\\u4EF6\\u540D\\u6A21\\u677F / File Name Template\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684\\u6587\\u4EF6\\u540D\\uFF08\\u4E0D\\u542B .md\\uFF09\\u3002\\u53EF\\u7528\\u53D8\\u91CF\\uFF1A{{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}} | File name (without .md). Variables: {{title}} {{arxivId}} {{date}} {{model}} {{year}} {{month}} {{day}}\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"{{title}}-deep-read-{{model}}\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) != null ? _b2 : \"\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n fileNameTemplate: value.trim()\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDeepReadFileName(template, paper, baseId, date, modelName) {\n var _a2;\n const safeStr = (s, maxLen = 60) => s.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/\\s+/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\").slice(0, maxLen);\n const [year, month, day] = date.split(\"-\");\n const modelShort = (_a2 = modelName.split(\"/\").pop()) != null ? _a2 : modelName;\n const vars = {\n title: safeStr(paper.title),\n arxivId: baseId,\n date,\n model: safeStr(modelShort, 40),\n year,\n month,\n day\n };\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result.replace(/[/\\\\:*?\"<>|]/g, \"-\").replace(/-+/g, \"-\").replace(/^-|-$/g, \"\") || baseId;\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2, _c, _d;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const fnTemplate = ((_b2 = (_a3 = settings.deepRead) == null ? void 0 : _a3.fileNameTemplate) == null ? void 0 : _b2.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, p, baseId, date, settings.llm.model);\n linkParts.push(`[[${deepReadFolder}/${date}/${fileName}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_c = p.llmSummary) != null ? _c : \"\");\n const hits = ((_d = p.interestHits) != null ? _d : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const fnTemplate = ((_C = (_B = settings.deepRead) == null ? void 0 : _B.fileNameTemplate) == null ? void 0 : _C.trim()) || \"{{title}}-deep-read-{{model}}\";\n const fileName = buildDeepReadFileName(fnTemplate, paper, baseId, date, settings.llm.model);\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_D = paper.authors) != null ? _D : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${fileName}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${fileName}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_F = (_E = settings.deepRead) == null ? void 0 : _E.enabled) != null ? _F : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_G = settings.hfSource) == null ? void 0 : _G.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_H = paper.categories) != null ? _H : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "79ac7e74021f5c923caf9adfce553bde6aca044b": {"t": 1785765905.6102924, "n": 228479, "h": "55de226f66e7b966", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(() => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n this.plugin.runBackfillWithUI(bfStartDate, bfEndDate);\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_B = paper.authors) != null ? _B : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_D = (_C = settings.deepRead) == null ? void 0 : _C.enabled) != null ? _D : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_E = settings.hfSource) == null ? void 0 : _E.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_F = paper.categories) != null ? _F : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n var _a2;\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n if ((_a2 = options.signal) == null ? void 0 : _a2.aborted)\n throw new PipelineAbortError();\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false,\n signal: options.signal\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop, title = \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\") {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const titleEl = header.createEl(\"span\", { text: title });\n titleEl.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n this.activeBackfillController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress, signal) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n signal,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n /** Run backfill pipeline with floating UI and stop button. */\n async runBackfillWithUI(startDate, endDate) {\n if (this.activeBackfillController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u6279\\u91CF\\u751F\\u6210\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeBackfillController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n }, \"\\u{1F4C5} \\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5\");\n try {\n await this.runBackfill(startDate, endDate, (msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeBackfillController = null;\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "c6b1e7ab2bd807d1ec673905c3db8f3b8cac5c7d": {"t": 1785765907.6436596, "n": 227551, "h": "a766f3073ec3efb5", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources\").setDesc(\"\\u{1F6A7} Coming Soon \\u2014 \\u81EA\\u5B9A\\u4E49 RSS/Atom \\u8BA2\\u9605\\u6E90\\u5C06\\u5728\\u540E\\u7EED\\u7248\\u672C\\u652F\\u6301 | Custom RSS/Atom feed ingestion is planned for a future release.\");\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5DE5\\u5177 / Tools\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(() => {\n this.plugin.runDailyWithUI();\n });\n });\n containerEl.createEl(\"h3\", { text: \"\\u6279\\u91CF\\u751F\\u6210\\u65E5\\u62A5 / Batch Generate Daily Reports\" });\n containerEl.createEl(\"p\", {\n text: \"\\u6309\\u65E5\\u671F\\u8303\\u56F4\\u6279\\u91CF\\u751F\\u6210\\u6BCF\\u65E5\\u62A5\\u544A\\uFF0C\\u9002\\u5408\\u8865\\u5168\\u5386\\u53F2\\u8BB0\\u5F55 | Generate daily reports for a date range to backfill historical records.\",\n cls: \"setting-item-description\"\n });\n let bfStartDate = \"\";\n let bfEndDate = \"\";\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u59CB\\u65E5\\u671F / Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n bfStartDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u7ED3\\u675F\\u65E5\\u671F / End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n bfEndDate = v.trim();\n }));\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u25B6 \\u6279\\u91CF\\u751F\\u6210 / Run Batch\").setCta().onClick(async () => {\n if (!bfStartDate || !bfEndDate) {\n setStatus(\"\\u8BF7\\u586B\\u5199\\u5F00\\u59CB\\u548C\\u7ED3\\u675F\\u65E5\\u671F\\u3002\", \"var(--color-red)\");\n return;\n }\n btn.setDisabled(true);\n setStatus(\"\\u6279\\u91CF\\u751F\\u6210\\u4E2D\\uFF0C\\u8BF7\\u7A0D\\u5019...\");\n try {\n await this.plugin.runBackfill(bfStartDate, bfEndDate, (msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 \\u9519\\u8BEF: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setDisabled(false);\n }\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nvar PipelineAbortError = class extends Error {\n constructor() {\n super(\"Pipeline aborted by user\");\n this.name = \"PipelineAbortError\";\n }\n};\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n const checkAbort = () => {\n var _a3;\n if ((_a3 = options.signal) == null ? void 0 : _a3.aborted)\n throw new PipelineAbortError();\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n checkAbort();\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n checkAbort();\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n checkAbort();\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_B = paper.authors) != null ? _B : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_D = (_C = settings.deepRead) == null ? void 0 : _C.enabled) != null ? _D : false})`);\n }\n checkAbort();\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_E = settings.hfSource) == null ? void 0 : _E.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_F = paper.categories) != null ? _F : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/ui/floatingProgress.ts\nvar FloatingProgress = class {\n constructor(onStop) {\n this.el = document.body.createDiv();\n this.el.style.cssText = [\n \"position:fixed\",\n \"bottom:24px\",\n \"right:24px\",\n \"z-index:9999\",\n \"background:var(--background-secondary)\",\n \"border:1px solid var(--background-modifier-border)\",\n \"border-radius:10px\",\n \"padding:14px 18px 12px\",\n \"min-width:300px\",\n \"max-width:420px\",\n \"box-shadow:0 4px 20px rgba(0,0,0,0.25)\",\n \"font-family:var(--font-interface)\"\n ].join(\";\");\n const header = this.el.createDiv();\n header.style.cssText = \"display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;\";\n const title = header.createEl(\"span\", { text: \"\\u{1F4DA} Paper Daily \\u8FD0\\u884C\\u4E2D\" });\n title.style.cssText = \"font-weight:600;font-size:0.92em;color:var(--text-normal);\";\n const stopBtn = header.createEl(\"button\", { text: \"\\u505C\\u6B62\" });\n stopBtn.style.cssText = [\n \"padding:2px 10px\",\n \"border-radius:4px\",\n \"cursor:pointer\",\n \"font-size:0.8em\",\n \"border:1px solid var(--text-error,#cc4444)\",\n \"color:var(--text-error,#cc4444)\",\n \"background:transparent\"\n ].join(\";\");\n stopBtn.onclick = () => {\n onStop();\n stopBtn.disabled = true;\n stopBtn.textContent = \"\\u505C\\u6B62\\u4E2D...\";\n };\n this.msgEl = this.el.createEl(\"div\");\n this.msgEl.style.cssText = \"font-size:0.83em;color:var(--text-muted);word-break:break-word;line-height:1.4;\";\n this.msgEl.setText(\"\\u521D\\u59CB\\u5316\\u4E2D...\");\n }\n setMessage(msg) {\n this.msgEl.setText(msg);\n }\n destroy() {\n this.el.remove();\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n constructor() {\n super(...arguments);\n this.activeAbortController = null;\n }\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n if (this.activeAbortController)\n return Promise.resolve();\n return this.runDailyWithUI();\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: () => {\n void this.runDailyWithUI();\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress, signal) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress, signal }\n );\n }\n /** Run daily pipeline with floating UI and stop button. */\n async runDailyWithUI() {\n if (this.activeAbortController) {\n new import_obsidian7.Notice(\"Paper Daily: \\u4EFB\\u52A1\\u5DF2\\u5728\\u8FD0\\u884C\\u4E2D\\u3002\");\n return;\n }\n const controller = new AbortController();\n this.activeAbortController = controller;\n const fp = new FloatingProgress(() => {\n controller.abort();\n });\n try {\n await this.runDaily((msg) => fp.setMessage(msg), controller.signal);\n fp.setMessage(\"\\u2705 \\u5B8C\\u6210\\uFF01\");\n setTimeout(() => fp.destroy(), 3e3);\n } catch (err) {\n if (err instanceof PipelineAbortError) {\n fp.setMessage(\"\\u23F9 \\u5DF2\\u505C\\u6B62\\u3002\");\n setTimeout(() => fp.destroy(), 2e3);\n } else {\n fp.setMessage(`\\u274C \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => fp.destroy(), 6e3);\n }\n } finally {\n this.activeAbortController = null;\n }\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n void this.runDailyWithUI();\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "7d44eba7d4a365e1c5e912819870d2794d88f5c7": {"t": 1785765909.6367888, "n": 226908, "h": "17d99d0757fb71f5", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b2 : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b2;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b2 = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b2 : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u914D\\u7F6E\\u6587\\u4EF6 / Config File\" });\n const configPath = `${this.plugin.settings.rootFolder}/config.json`;\n new import_obsidian.Setting(containerEl).setName(\"\\u914D\\u7F6E\\u6587\\u4EF6\\u8DEF\\u5F84 / Config File Path\").setDesc(`\\u6240\\u6709\\u8BBE\\u7F6E\\u81EA\\u52A8\\u540C\\u6B65\\u5230\\u6B64 Vault \\u6587\\u4EF6\\uFF0C\\u6362\\u8BBE\\u5907\\u6216\\u91CD\\u88C5\\u63D2\\u4EF6\\u65F6\\u5C06\\u4F18\\u5148\\u4ECE\\u6B64\\u6587\\u4EF6\\u8BFB\\u53D6\\u3002| All settings are auto-synced to this vault file and loaded on startup.`).addText((text) => {\n text.setValue(configPath);\n text.inputEl.readOnly = true;\n text.inputEl.style.width = \"100%\";\n text.inputEl.style.color = \"var(--text-muted)\";\n text.inputEl.style.fontFamily = \"monospace\";\n text.inputEl.style.fontSize = \"0.85em\";\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u7ACB\\u5373\\u5BFC\\u51FA / Export Now\").setCta().onClick(async () => {\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u914D\\u7F6E\\u5DF2\\u5BFC\\u51FA\\u5230 ${configPath}`);\n })).addButton((btn) => btn.setButtonText(\"\\u4ECE\\u6587\\u4EF6\\u91CD\\u8F7D / Reload from File\").onClick(async () => {\n await this.plugin.loadSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u4ECE\\u914D\\u7F6E\\u6587\\u4EF6\\u91CD\\u65B0\\u52A0\\u8F7D\\u8BBE\\u7F6E\\u3002\");\n this.display();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_B = paper.authors) != null ? _B : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_D = (_C = settings.deepRead) == null ? void 0 : _C.enabled) != null ? _D : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_E = settings.hfSource) == null ? void 0 : _E.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_F = paper.categories) != null ? _F : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n var _a2, _b;\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n const locale = (_b = (_a2 = window.moment) == null ? void 0 : _a2.locale()) != null ? _b : \"\";\n this.settings.language = locale.startsWith(\"zh\") ? \"zh\" : \"en\";\n await this.loadSettingsFromVaultFile();\n }\n async saveSettings() {\n await this.saveData(this.settings);\n void this.saveSettingsToVaultFile();\n }\n get configFilePath() {\n return `${this.settings.rootFolder}/config.json`;\n }\n async loadSettingsFromVaultFile() {\n try {\n const file = this.app.vault.getAbstractFileByPath((0, import_obsidian7.normalizePath)(this.configFilePath));\n if (!(file instanceof import_obsidian7.TFile))\n return;\n const content = await this.app.vault.read(file);\n const vaultSettings = JSON.parse(content);\n this.settings = Object.assign({}, this.settings, vaultSettings);\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n console.log(`[PaperDaily] Loaded settings from vault: ${this.configFilePath}`);\n } catch (e) {\n }\n }\n async saveSettingsToVaultFile() {\n try {\n const writer = new VaultWriter(this.app);\n await writer.writeNote(this.configFilePath, JSON.stringify(this.settings, null, 2));\n } catch (e) {\n console.error(\"[PaperDaily] Failed to write vault config file:\", e);\n }\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "6270f28a286dd790e481ea651701e2b72eb0936e": {"t": 1785765911.6526203, "n": 225221, "h": "76f69734156270ef", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2, _b;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n this.display();\n });\n });\n if (((_a2 = this.plugin.settings.hfSource) == null ? void 0 : _a2.enabled) !== false) {\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u56DE\\u6EAF\\u5929\\u6570 / HuggingFace Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HuggingFace papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(0, 7, 1).setValue((_b2 = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b2 : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b2;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b2 = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b2 : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b2, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b2 = TYPE_COLORS[tplType]) != null ? _b2 : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_b = lib.find((t) => t.id === selectedId)) != null ? _b : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b2 : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b2;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b2 = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b2 : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b2;\n return toggle.setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b2 : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(1, 10, 1).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b2 : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b2;\n return slider.setLimits(256, 4096, 128).setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b2 : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b2 : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b2;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b2 = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b2 : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, domainSummary, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (domainSummary)\n sections.push(\"\", domainSummary);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n const catStats = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_q = paper.categories) != null ? _q : []) {\n if (!catStats.has(cat))\n catStats.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats = [...catStats.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const hotnessProgressStr = topCats.map(\n ([cat, s]) => `${cat} ${s.count}\\u7BC7${s.scored > 0 ? ` avg${(s.totalScore / s.scored).toFixed(1)}` : \"\"}`\n ).join(\" \\xB7 \");\n progress(`\\u{1F4CA} \\u9886\\u57DF\\u70ED\\u5EA6: ${hotnessProgressStr}`);\n log(`Step 3b DOMAIN HOTNESS: ${hotnessProgressStr}`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_r = settings.deepRead) == null ? void 0 : _r.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_s = settings.deepRead.topN) != null ? _s : 5, rankedPapers.length);\n const maxTokens = (_t = settings.deepRead.deepReadMaxTokens) != null ? _t : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_B = paper.authors) != null ? _B : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_D = (_C = settings.deepRead) == null ? void 0 : _C.enabled) != null ? _D : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_E = settings.hfSource) == null ? void 0 : _E.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const catStats2 = /* @__PURE__ */ new Map();\n for (const paper of rankedPapers) {\n for (const cat of (_F = paper.categories) != null ? _F : []) {\n if (!catStats2.has(cat))\n catStats2.set(cat, { count: 0, totalScore: 0, scored: 0 });\n const s = catStats2.get(cat);\n s.count++;\n if (paper.llmScore != null) {\n s.totalScore += paper.llmScore;\n s.scored++;\n }\n }\n }\n const topCats2 = [...catStats2.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, 10);\n const domainSummary = topCats2.length > 0 ? [\n \"## \\u9886\\u57DF\\u70ED\\u5EA6 / Domain Hotness\",\n \"\",\n \"| \\u9886\\u57DF | \\u8BBA\\u6587\\u6570 | \\u5E73\\u5747\\u5206 |\",\n \"|------|--------|--------|\",\n ...topCats2.map(\n ([cat, s]) => `| ${cat} | ${s.count} | ${s.scored > 0 ? (s.totalScore / s.scored).toFixed(1) : \"-\"} |`\n )\n ].join(\"\\n\") : \"\";\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, domainSummary, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "f6187f4d1bffa9aa14526f4e3dd9900ac68aa90c": {"t": 1785765914.1231732, "n": 223148, "h": "2339d81cef21c072", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F917} HF \\u70ED\\u5EA6: {hfUpvotes} \\u8D5E \\u2190 **only include this line if hfUpvotes > 0 for this paper; omit entirely otherwise**\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_D = settings.hfSource) == null ? void 0 : _D.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "afd527c47dced3b3b0d11c5efb3e4ffb7014690a": {"t": 1785765916.5981836, "n": 223008, "h": "41d3f86414e65fd6", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\n{{hf_data_section}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n{{hf_signal_section}}\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HuggingFace \\u8BBA\\u6587\\u6E90 / HuggingFace Source\").setDesc(\"\\u5F00\\u542F\\u540E\\u6293\\u53D6 huggingface.co/papers \\u6BCF\\u65E5\\u7CBE\\u9009\\uFF0C\\u4E0E arXiv \\u7ED3\\u679C\\u5408\\u5E76\\u6392\\u540D | Fetch HuggingFace daily papers and merge with arXiv results\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue(((_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.enabled) !== false).onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 20 \\u7BC7\\uFF0C\\u542B arXiv + HF\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_data_section}}\", \"HF \\u6570\\u636E\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u542B\\u6807\\u9898+JSON\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_signal_section}}\", \"HF \\u793E\\u533A\\u4FE1\\u53F7\\u6307\\u4EE4\\u5757\\uFF08HF \\u5F00\\u542F\\u65F6\\u6CE8\\u5165\\uFF0C\\u5173\\u95ED\\u65F6\\u4E3A\\u7A7A\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const hfEnabled = ((_D = settings.hfSource) == null ? void 0 : _D.enabled) !== false && hfDailyPapers.length > 0;\n const hfDataSection = hfEnabled ? `Note: papers with \"source\": \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n${JSON.stringify(hfForLLM, null, 2)}` : \"\";\n const hfSignalSection = hfEnabled ? `### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n hf_data_section: hfDataSection,\n hf_signal_section: hfSignalSection,\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "d726ec7ad5162d684fe29d0c0ec357d866d42aca": {"t": 1785765918.5425496, "n": 221909, "h": "1d88f075516edba9", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\nNote: papers with a \"source\" field of \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers \\u2014 same depth of analysis, same rating criteria.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const typeSelect = tabBar.createEl(\"select\");\n typeSelect.style.cssText = \"padding:4px 8px;border-radius:5px;font-size:0.85em;border:1px solid var(--background-modifier-border);background:var(--background-secondary);color:var(--text-normal);cursor:pointer;\";\n [[\"daily\", \"\\u65E5\\u62A5\"], [\"scoring\", \"\\u8BC4\\u5206\"], [\"deepread\", \"\\u7CBE\\u8BFB\"]].forEach(([val, label]) => {\n const o = typeSelect.createEl(\"option\", { text: label });\n o.value = val;\n });\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newType = typeSelect.value;\n const defaultPrompt = newType === \"scoring\" ? DEFAULT_SCORING_PROMPT : newType === \"deepread\" ? DEFAULT_DEEP_READ_PROMPT : DEFAULT_DAILY_PROMPT;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: newType,\n prompt: defaultPrompt\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n await setActiveIdForType(newType, newTpl.id);\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${date}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = `${(_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\"}/${date}`;\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "b607750c32374ed830413071600ee61e27e6f296": {"t": 1785765920.9291718, "n": 221197, "h": "36156f1cb239a2ab", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked, arXiv + HuggingFace combined):\n{{papers_json}}\n\nNote: papers with a \"source\" field of \"hf\" are HuggingFace-only picks. Treat them identically to arXiv papers \\u2014 same depth of analysis, same rating criteria.\n\n## HuggingFace Daily Papers (full list for reference, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from the paper data (arXiv / HF / PDF as available)\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace full list, note any papers NOT already covered above. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- HuggingFace papers in papers_json must receive the same full analysis treatment as arXiv papers.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: \"daily\",\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2, _b;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const deepReadFolder = (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.outputFolder) != null ? _b : \"PaperDaily/deep-read\";\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b2;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[[${p.links.localPdf}|Local PDF]]`);\n if (p.deepReadAnalysis) {\n const baseId = p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n linkParts.push(`[[${deepReadFolder}/${safeId}|Deep Read]]`);\n }\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b2 = p.interestHits) != null ? _b2 : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 20);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "78d8748fbc5f6f57ba2d26c6c7d199f8ec414298": {"t": 1785765923.6125624, "n": 220810, "h": "4bc4babe582ec858", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked by HF upvotes + keyword weight):\n{{papers_json}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n{{local_pdfs}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from paper data. If a local PDF path is listed in the Local PDFs section above, include it here as \"[[Local PDF]]\".\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- If local_pdfs is non-empty, include the local PDF link in the \\u{1F517} line of the corresponding paper.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: \"daily\",\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a2, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a2 = p.llmSummary) != null ? _a2 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 10;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "4a83453e907675d50554f74ba4c64de4f0f1d951": {"t": 1785765926.1573145, "n": 220810, "h": "651fb44dfa8b0aea", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked by HF upvotes + keyword weight):\n{{papers_json}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n{{local_pdfs}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from paper data. If a local PDF path is listed in the Local PDFs section above, include it here as \"[[Local PDF]]\".\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- If local_pdfs is non-empty, include the local PDF link in the \\u{1F517} line of the corresponding paper.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: \"daily\",\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a2, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a2 = p.llmSummary) != null ? _a2 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 \\u5171 ${topN} \\u7BC7...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n progress(`[3/5] \\u{1F4D6} Deep Read (${i + 1}/${topN})...`);\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "516f50b59b3a85e3935c903aee2e0905bfb7dbee": {"t": 1785765928.5238354, "n": 220754, "h": "903a9b9a5206100b", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked by HF upvotes + keyword weight):\n{{papers_json}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n{{local_pdfs}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from paper data. If a local PDF path is listed in the Local PDFs section above, include it here as \"[[Local PDF]]\".\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- If local_pdfs is non-empty, include the local PDF link in the \\u{1F517} line of the corresponding paper.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: \"daily\",\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a2, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a2 = p.llmSummary) != null ? _a2 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n const paperFrom = batchStart + 1;\n const paperTo = batchStart + batchPapers.length;\n const paperTotal = rankedPapers.length;\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${paperFrom}\\u2013${paperTo} / ${paperTotal} \\u7BC7)...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "094f9825dd26d7787e2906db25dffdf1a6e182b8": {"t": 1785765930.6270654, "n": 220622, "h": "73c94031553b3bd5", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked by HF upvotes + keyword weight):\n{{papers_json}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n{{local_pdfs}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from paper data. If a local PDF path is listed in the Local PDFs section above, include it here as \"[[Local PDF]]\".\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- If local_pdfs is non-empty, include the local PDF link in the \\u{1F517} line of the corresponding paper.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: \"daily\",\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a2, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a2 = p.llmSummary) != null ? _a2 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${batchIdx + 1}/${totalBatches}) ${batchPapers.length} \\u7BC7...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: \"\",\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "9a891cfc594f0cd84a73103348da2e32788904b9": {"t": 1785765932.4638786, "n": 221394, "h": "b42c28834cec4dd0", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked by HF upvotes + keyword weight):\n{{papers_json}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n{{local_pdfs}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from paper data. If a local PDF path is listed in the Local PDFs section above, include it here as \"[[Local PDF]]\".\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- If local_pdfs is non-empty, include the local PDF link in the \\u{1F517} line of the corresponding paper.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", type: \"daily\", prompt: DEFAULT_DAILY_PROMPT, builtin: true },\n { id: \"builtin_scoring\", name: \"\\u6279\\u91CF\\u8BC4\\u5206\", type: \"scoring\", prompt: DEFAULT_SCORING_PROMPT, builtin: true },\n { id: \"builtin_deepread\", name: \"\\u5168\\u6587\\u7CBE\\u8BFB\", type: \"deepread\", prompt: DEFAULT_DEEP_READ_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\",\n activeScorePromptId: \"builtin_scoring\",\n activeDeepReadPromptId: \"builtin_deepread\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const TYPE_LABELS = { daily: \"\\u65E5\\u62A5\", scoring: \"\\u8BC4\\u5206\", deepread: \"\\u7CBE\\u8BFB\" };\n const TYPE_COLORS = { daily: \"#4a90d9\", scoring: \"#5cb85c\", deepread: \"#9b59b6\" };\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u53EF\\u5207\\u6362\\u6A21\\u677F\\u5E76\\u5C06\\u5176\\u8BBE\\u4E3A\\u5BF9\\u5E94\\u529F\\u80FD\\u7684\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"[\\u65E5\\u62A5] {{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F YYYY-MM-DD\"],\n [\"[\\u65E5\\u62A5] {{papers_json}}\", \"\\u6392\\u540D\\u540E\\u8BBA\\u6587\\u5217\\u8868 JSON\\uFF08\\u6700\\u591A 10 \\u7BC7\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{hf_papers_json}}\", \"HF Daily Papers JSON\\uFF08\\u6700\\u591A 15 \\u6761\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{local_pdfs}}\", \"\\u5DF2\\u4E0B\\u8F7D\\u672C\\u5730 PDF \\u5217\\u8868\\uFF08Markdown\\uFF09\"],\n [\"[\\u65E5\\u62A5] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u65E5\\u62A5] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"],\n [\"[\\u8BC4\\u5206] {{interest_keywords}}\", \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u53CA\\u6743\\u91CD\"],\n [\"[\\u8BC4\\u5206] {{papers_json}}\", \"\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF08\\u542B id/title/abstract/interestHits/hfUpvotes\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{title}} {{authors}}\", \"\\u8BBA\\u6587\\u6807\\u9898 / \\u524D 5 \\u4F4D\\u4F5C\\u8005\"],\n [\"[\\u7CBE\\u8BFB] {{published}} {{arxiv_url}}\", \"\\u53D1\\u5E03\\u65E5\\u671F / arXiv \\u94FE\\u63A5\"],\n [\"[\\u7CBE\\u8BFB] {{interest_hits}}\", \"\\u547D\\u4E2D\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\"],\n [\"[\\u7CBE\\u8BFB] {{abstract}}\", \"\\u6458\\u8981\\u5168\\u6587\"],\n [\"[\\u7CBE\\u8BFB] {{fulltext}}\", \"arxiv.org/html URL\\uFF08\\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\uFF09\"],\n [\"[\\u7CBE\\u8BFB] {{language}}\", \"Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n }\n const lib = this.plugin.settings.promptLibrary;\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n if (!lib.find((t) => t.id === def.id))\n lib.push({ ...def });\n }\n for (const def of DEFAULT_PROMPT_LIBRARY) {\n const existing = lib.find((t) => t.id === def.id);\n if (existing && !existing.type)\n existing.type = def.type;\n }\n if (!this.plugin.settings.activePromptId)\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n if (!this.plugin.settings.activeScorePromptId)\n this.plugin.settings.activeScorePromptId = \"builtin_scoring\";\n if (!this.plugin.settings.activeDeepReadPromptId)\n this.plugin.settings.activeDeepReadPromptId = \"builtin_deepread\";\n const getActiveIdForType = (type) => {\n if (type === \"scoring\")\n return this.plugin.settings.activeScorePromptId;\n if (type === \"deepread\")\n return this.plugin.settings.activeDeepReadPromptId;\n return this.plugin.settings.activePromptId;\n };\n const setActiveIdForType = async (type, id) => {\n if (type === \"scoring\")\n this.plugin.settings.activeScorePromptId = id;\n else if (type === \"deepread\")\n this.plugin.settings.activeDeepReadPromptId = id;\n else\n this.plugin.settings.activePromptId = id;\n await this.plugin.saveSettings();\n };\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n var _a3, _b, _c;\n tabBar.empty();\n for (const tpl of lib) {\n const tplType = (_a3 = tpl.type) != null ? _a3 : \"daily\";\n const activeIdForType = getActiveIdForType(tplType);\n const isSelected = tpl.id === selectedId;\n const isActiveForType = tpl.id === activeIdForType;\n const typeColor = (_b = TYPE_COLORS[tplType]) != null ? _b : \"#888\";\n const typeLabel = (_c = TYPE_LABELS[tplType]) != null ? _c : tplType;\n const btn = tabBar.createEl(\"button\");\n const badge = btn.createEl(\"span\", { text: typeLabel });\n badge.style.cssText = `display:inline-block;font-size:0.75em;padding:1px 5px;border-radius:3px;margin-right:5px;background:${typeColor};color:#fff;font-weight:600;vertical-align:middle;`;\n btn.appendText(tpl.name);\n if (isActiveForType) {\n const dot = btn.createEl(\"span\", { text: \" \\u2713\" });\n dot.style.cssText = `color:${typeColor};font-weight:700;`;\n }\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 12px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = async () => {\n selectedId = tpl.id;\n await setActiveIdForType(tplType, tpl.id);\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib.filter((t) => !t.builtin).length + 1}`,\n type: \"daily\",\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n var _a3;\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n const prevTpl = lib.find((t) => t.id === selectedId);\n await setActiveIdForType((_a3 = prevTpl.type) != null ? _a3 : \"daily\", selectedId);\n promptTA.value = prevTpl.prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = lib.find((t) => t.id === selectedId)) != null ? _a2 : lib[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction getActiveScoringPrompt(settings) {\n var _a2;\n if (settings.promptLibrary && settings.activeScorePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeScorePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_a2 = settings.scoringPromptTemplate) != null ? _a2 : DEFAULT_SCORING_PROMPT;\n}\nfunction getActiveDeepReadPrompt(settings) {\n var _a2, _b;\n if (settings.promptLibrary && settings.activeDeepReadPromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activeDeepReadPromptId);\n if (tpl)\n return tpl.prompt;\n }\n return (_b = (_a2 = settings.deepRead) == null ? void 0 : _a2.deepReadPromptTemplate) != null ? _b : DEFAULT_DEEP_READ_PROMPT;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n let localPdfsSection = \"\";\n if ((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf) {\n const pdfsWithLocal = rankedPapers.filter((p) => p.links.localPdf);\n if (pdfsWithLocal.length > 0) {\n const lines = pdfsWithLocal.map(\n (p) => `- [${p.title}](${p.links.localPdf})`\n );\n localPdfsSection = `## \\u672C\\u5730 PDF / Local PDFs (${pdfsWithLocal.length} \\u7BC7)\n\n${lines.join(\"\\n\")}`;\n }\n }\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (localPdfsSection)\n sections.push(\"\", localPdfsSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = getActiveScoringPrompt(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${batchIdx + 1}/${totalBatches}) ${batchPapers.length} \\u7BC7...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = getActiveDeepReadPrompt(settings);\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_t = paper.authors) != null ? _t : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_u = paper.interestHits) != null ? _u : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_w = (_v = settings.deepRead) == null ? void 0 : _v.outputFolder) != null ? _w : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_y = (_x = settings.deepRead) == null ? void 0 : _x.tags) != null ? _y : [\"paper\", \"deep-read\"],\n ...((_z = paper.interestHits) != null ? _z : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_A = paper.authors) != null ? _A : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_C = (_B = settings.deepRead) == null ? void 0 : _B.enabled) != null ? _C : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const localPdfEntries = rankedPapers.filter((p) => p.links.localPdf).map((p) => `- [${p.title}](${p.links.localPdf})`);\n const localPdfsSection = localPdfEntries.length > 0 ? `## Local PDFs (${date})\n${localPdfEntries.join(\"\\n\")}` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: localPdfsSection,\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "72ec384041d38359b15b3b37eeab8259dfe41490": {"t": 1785765934.6217244, "n": 220524, "h": "3a71f7123fd7ab87", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n---\n\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## Papers to analyze (pre-ranked by HF upvotes + keyword weight):\n{{papers_json}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n{{fulltext_section}}\n\n{{local_pdfs}}\n\n---\n\n## Instructions\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the papers list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n > If a Deep Read note exists for this paper (see fulltext_section above), draw directly from it here and in \\u5DE5\\u7A0B\\u542F\\u793A / \\u5C40\\u9650\\u6027. Prefer that analysis over the abstract.\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\".\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} links from paper data. If a local PDF path is listed in the Local PDFs section above, include it here as \"[[Local PDF]]\".\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.\n- If fulltext_section is non-empty, you MUST use those deep-read notes to enrich the analysis of the corresponding papers. Do not ignore them.\n- If local_pdfs is non-empty, include the local PDF link in the \\u{1F517} line of the corresponding paper.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u6BCF\\u65E5trending\", prompt: DEFAULT_DAILY_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u5207\\u6362\\u5E76\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"{{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F\\uFF0C\\u683C\\u5F0F YYYY-MM-DD\"],\n [\"{{papers_json}}\", \"\\u6392\\u540D\\u540E\\u7684 arXiv + HF \\u8BBA\\u6587\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u6BCF\\u7BC7\\u542B id / title / abstract / interestHits / hfUpvotes / links \\u7B49\\u5B57\\u6BB5\\uFF0C\\u6700\\u591A 10 \\u7BC7\"],\n [\"{{hf_papers_json}}\", \"HuggingFace Daily Papers \\u539F\\u59CB\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u542B title / hfUpvotes / streakDays\\uFF0C\\u6700\\u591A 15 \\u6761\"],\n [\"{{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\\uFF1B\\u6BCF\\u7BC7\\u901A\\u8FC7 arxiv.org/html URL \\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\u539F\\u6587\\u5E76\\u751F\\u6210\\u5206\\u6790\\uFF1B\\u672A\\u5F00\\u542F Deep Read \\u65F6\\u4E3A\\u7A7A\"],\n [\"{{local_pdfs}}\", \"\\u5F53\\u65E5\\u5DF2\\u4E0B\\u8F7D\\u5230\\u672C\\u5730\\u7684 PDF \\u5217\\u8868\\uFF08Markdown \\u94FE\\u63A5\\uFF09\\uFF1B\\u672A\\u5F00\\u542F PDF \\u4E0B\\u8F7D\\u65F6\\u4E3A\\u7A7A\\u5B57\\u7B26\\u4E32\"],\n [\"{{interest_keywords}}\", \"\\u7528\\u6237\\u914D\\u7F6E\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u5217\\u8868\\uFF0C\\u542B\\u6743\\u91CD\\uFF0C\\u683C\\u5F0F\\u5982 rlhf(weight:5), agent(weight:5)\\uFF0C\\u4F9B\\u6A21\\u578B\\u53C2\\u8003\\u4F18\\u5148\\u7EA7\"],\n [\"{{language}}\", \"\\u8F93\\u51FA\\u8BED\\u8A00\\uFF0C\\u7531\\u8BBE\\u7F6E\\u4E2D'\\u8BED\\u8A00'\\u9009\\u9879\\u51B3\\u5B9A\\uFF0C\\u503C\\u4E3A Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n }\n if (!this.plugin.settings.activePromptId) {\n this.plugin.settings.activePromptId = this.plugin.settings.promptLibrary[0].id;\n }\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n tabBar.empty();\n const lib = this.plugin.settings.promptLibrary;\n for (const tpl of lib) {\n const isSelected = tpl.id === selectedId;\n const btn = tabBar.createEl(\"button\", { text: tpl.name });\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 14px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = () => {\n selectedId = tpl.id;\n this.plugin.settings.activePromptId = tpl.id;\n this.plugin.saveSettings();\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const lib2 = this.plugin.settings.promptLibrary;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib2.filter((t) => !t.builtin).length + 1}`,\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib2.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const lib = this.plugin.settings.promptLibrary;\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n this.plugin.settings.activePromptId = selectedId;\n promptTA.value = lib.find((t) => t.id === selectedId).prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = this.plugin.settings.promptLibrary.find((t) => t.id === selectedId)) != null ? _a2 : this.plugin.settings.promptLibrary[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u8BC4\\u5206 Prompt / Scoring Prompt\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BC4\\u5206 Prompt / Scoring Prompt\").setDesc(\n '\\u6BCF\\u6279\\u8BBA\\u6587\\u7684\\u5FEB\\u901F\\u6253\\u5206 Prompt\\u3002\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\n\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A{{interest_keywords}}\\uFF08\\u5174\\u8DA3\\u5173\\u952E\\u8BCD+\\u6743\\u91CD\\uFF09\\uFF0C{{papers_json}}\\uFF08\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF09\\n\\u5FC5\\u987B\\u8981\\u6C42\\u6A21\\u578B\\u8FD4\\u56DE JSON \\u6570\\u7EC4\\uFF0C\\u683C\\u5F0F\\uFF1A[{\"id\":\"arxiv:...\",\"score\":1-10,\"reason\":\"...\",\"summary\":\"...\"}]'\n ).addTextArea((area) => {\n var _a3;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_a3 = this.plugin.settings.scoringPromptTemplate) != null ? _a3 : \"\");\n area.inputEl.rows = 10;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n this.plugin.settings.scoringPromptTemplate = val || void 0;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset to Default\").onClick(async () => {\n this.plugin.settings.scoringPromptTemplate = void 0;\n await this.plugin.saveSettings();\n this.display();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u7CBE\\u8BFB Prompt / Per-paper Deep Read prompt\").setDesc(\n \"\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u53D8\\u91CF: {{title}}, {{authors}}, {{published}}, {{arxiv_url}}, {{interest_hits}}, {{abstract}}, {{fulltext}}, {{language}}\"\n ).addTextArea((area) => {\n var _a3, _b;\n const plugin = this.plugin;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_b = (_a3 = plugin.settings.deepRead) == null ? void 0 : _a3.deepReadPromptTemplate) != null ? _b : \"\");\n area.inputEl.rows = 8;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n plugin.settings.deepRead = {\n ...plugin.settings.deepRead,\n deepReadPromptTemplate: val || void 0\n };\n await plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n let localPdfsSection = \"\";\n if ((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf) {\n const pdfsWithLocal = rankedPapers.filter((p) => p.links.localPdf);\n if (pdfsWithLocal.length > 0) {\n const lines = pdfsWithLocal.map(\n (p) => `- [${p.title}](${p.links.localPdf})`\n );\n localPdfsSection = `## \\u672C\\u5730 PDF / Local PDFs (${pdfsWithLocal.length} \\u7BC7)\n\n${lines.join(\"\\n\")}`;\n }\n }\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (localPdfsSection)\n sections.push(\"\", localPdfsSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = settings.scoringPromptTemplate || DEFAULT_SCORING_PROMPT;\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${batchIdx + 1}/${totalBatches}) ${batchPapers.length} \\u7BC7...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = (_t = settings.deepRead.deepReadPromptTemplate) != null ? _t : DEFAULT_DEEP_READ_PROMPT;\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_B = paper.authors) != null ? _B : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_D = (_C = settings.deepRead) == null ? void 0 : _C.enabled) != null ? _D : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const localPdfEntries = rankedPapers.filter((p) => p.links.localPdf).map((p) => `- [${p.title}](${p.links.localPdf})`);\n const localPdfsSection = localPdfEntries.length > 0 ? `## Local PDFs (${date})\n${localPdfEntries.join(\"\\n\")}` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: localPdfsSection,\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "6bad94687004e5ac1c8acd78e812aaab846f9d8f": {"t": 1785765936.7451096, "n": 220115, "h": "a75c827c6f896a85", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n## Context\nPapers below (arXiv + HF) have been pre-ranked by: HuggingFace upvotes \\u2192 interest keyword weight.\n\n## Papers to analyze (pre-ranked, arXiv + HF):\n{{papers_json}}\n{{fulltext_section}}\n{{local_pdfs}}\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n---\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\". If full text is available above, draw from methods/experiments.\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} {links from the paper data}\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Write a self-contained deep-read note for this paper \\u2014 it will be saved as a standalone Markdown reference document.\n\n**Paper:**\nTitle: {{title}}\nAuthors: {{authors}}\nPublished: {{published}}\narXiv: {{arxiv_url}}\nKeyword hits: {{interest_hits}}\n\n**Abstract:**\n{{abstract}}\n\n**Full paper** (read directly if the URL is accessible): {{fulltext}}\n\n---\n\nWrite the note with the following Markdown sections. Be direct, opinionated, and technically precise. No filler phrases.\n\n## TL;DR\nOne sentence: what they built/proved + the single most important result number.\n\n## \\u6838\\u5FC3\\u8D21\\u732E / Core Contribution\n2\\u20133 sentences. What exactly is new? Method name, dataset, metric, key numbers.\n\n## \\u65B9\\u6CD5 / Method\n3\\u20135 bullet points. Key technical decisions and why they matter. What distinguishes this from prior work at the mechanism level?\n\n## \\u5B9E\\u9A8C\\u7ED3\\u679C / Results\n- Which benchmarks / tasks\n- Headline numbers vs strongest baseline (exact figures)\n- Key ablation finding (if any)\n- What is suspiciously missing or underreported?\n\n## \\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway\n1\\u20132 sentences. What can a practitioner directly adopt? \"Use X to achieve Y\" \\u2014 not \"this is interesting\".\n\n## \\u5C40\\u9650\\u6027 / Limitations\n1\\u20132 sentences. Scope, compute requirements, reproducibility, failure modes in production.\n\n## \\u76F8\\u5173\\u5DE5\\u4F5C / Related Work\n2\\u20133 papers this most directly builds on or competes with. One line each: title + why it's relevant.\n\n---\nOutput language: {{language}}\nAim for 400\\u2013600 words total. Do not copy the abstract verbatim \\u2014 synthesize.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u5DE5\\u7A0B\\u7CBE\\u8BFB\", prompt: DEFAULT_DAILY_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 2048,\n outputFolder: \"PaperDaily/deep-read\",\n tags: [\"paper\", \"deep-read\"]\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u5207\\u6362\\u5E76\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"{{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F\\uFF0C\\u683C\\u5F0F YYYY-MM-DD\"],\n [\"{{papers_json}}\", \"\\u6392\\u540D\\u540E\\u7684 arXiv + HF \\u8BBA\\u6587\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u6BCF\\u7BC7\\u542B id / title / abstract / interestHits / hfUpvotes / links \\u7B49\\u5B57\\u6BB5\\uFF0C\\u6700\\u591A 10 \\u7BC7\"],\n [\"{{hf_papers_json}}\", \"HuggingFace Daily Papers \\u539F\\u59CB\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u542B title / hfUpvotes / streakDays\\uFF0C\\u6700\\u591A 15 \\u6761\"],\n [\"{{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\\uFF1B\\u6BCF\\u7BC7\\u901A\\u8FC7 arxiv.org/html URL \\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\u539F\\u6587\\u5E76\\u751F\\u6210\\u5206\\u6790\\uFF1B\\u672A\\u5F00\\u542F Deep Read \\u65F6\\u4E3A\\u7A7A\"],\n [\"{{local_pdfs}}\", \"\\u5F53\\u65E5\\u5DF2\\u4E0B\\u8F7D\\u5230\\u672C\\u5730\\u7684 PDF \\u5217\\u8868\\uFF08Markdown \\u94FE\\u63A5\\uFF09\\uFF1B\\u672A\\u5F00\\u542F PDF \\u4E0B\\u8F7D\\u65F6\\u4E3A\\u7A7A\\u5B57\\u7B26\\u4E32\"],\n [\"{{interest_keywords}}\", \"\\u7528\\u6237\\u914D\\u7F6E\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u5217\\u8868\\uFF0C\\u542B\\u6743\\u91CD\\uFF0C\\u683C\\u5F0F\\u5982 rlhf(weight:5), agent(weight:5)\\uFF0C\\u4F9B\\u6A21\\u578B\\u53C2\\u8003\\u4F18\\u5148\\u7EA7\"],\n [\"{{language}}\", \"\\u8F93\\u51FA\\u8BED\\u8A00\\uFF0C\\u7531\\u8BBE\\u7F6E\\u4E2D'\\u8BED\\u8A00'\\u9009\\u9879\\u51B3\\u5B9A\\uFF0C\\u503C\\u4E3A Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n }\n if (!this.plugin.settings.activePromptId) {\n this.plugin.settings.activePromptId = this.plugin.settings.promptLibrary[0].id;\n }\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n tabBar.empty();\n const lib = this.plugin.settings.promptLibrary;\n for (const tpl of lib) {\n const isSelected = tpl.id === selectedId;\n const btn = tabBar.createEl(\"button\", { text: tpl.name });\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 14px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = () => {\n selectedId = tpl.id;\n this.plugin.settings.activePromptId = tpl.id;\n this.plugin.saveSettings();\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const lib2 = this.plugin.settings.promptLibrary;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib2.filter((t) => !t.builtin).length + 1}`,\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib2.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const lib = this.plugin.settings.promptLibrary;\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n this.plugin.settings.activePromptId = selectedId;\n promptTA.value = lib.find((t) => t.id === selectedId).prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = this.plugin.settings.promptLibrary.find((t) => t.id === selectedId)) != null ? _a2 : this.plugin.settings.promptLibrary[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u8BC4\\u5206 Prompt / Scoring Prompt\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BC4\\u5206 Prompt / Scoring Prompt\").setDesc(\n '\\u6BCF\\u6279\\u8BBA\\u6587\\u7684\\u5FEB\\u901F\\u6253\\u5206 Prompt\\u3002\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\n\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A{{interest_keywords}}\\uFF08\\u5174\\u8DA3\\u5173\\u952E\\u8BCD+\\u6743\\u91CD\\uFF09\\uFF0C{{papers_json}}\\uFF08\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF09\\n\\u5FC5\\u987B\\u8981\\u6C42\\u6A21\\u578B\\u8FD4\\u56DE JSON \\u6570\\u7EC4\\uFF0C\\u683C\\u5F0F\\uFF1A[{\"id\":\"arxiv:...\",\"score\":1-10,\"reason\":\"...\",\"summary\":\"...\"}]'\n ).addTextArea((area) => {\n var _a3;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_a3 = this.plugin.settings.scoringPromptTemplate) != null ? _a3 : \"\");\n area.inputEl.rows = 10;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n this.plugin.settings.scoringPromptTemplate = val || void 0;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset to Default\").onClick(async () => {\n this.plugin.settings.scoringPromptTemplate = void 0;\n await this.plugin.saveSettings();\n this.display();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u8F93\\u51FA\\u76EE\\u5F55 / Output Folder\").setDesc(\"\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u4FDD\\u5B58\\u76EE\\u5F55\\uFF08Vault \\u5185\\u8DEF\\u5F84\\uFF09| Vault folder path for per-paper deep-read notes\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"PaperDaily/deep-read\").setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.outputFolder) != null ? _b : \"PaperDaily/deep-read\").onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n outputFolder: value.trim() || \"PaperDaily/deep-read\"\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6807\\u7B7E / Tags\").setDesc(\"\\u9017\\u53F7\\u5206\\u9694\\uFF0C\\u5199\\u5165\\u6BCF\\u7BC7\\u7CBE\\u8BFB\\u7B14\\u8BB0\\u7684 frontmatter tags | Comma-separated tags added to each paper note's frontmatter\").addText((text) => {\n var _a3, _b;\n return text.setPlaceholder(\"paper, deep-read\").setValue(((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.tags) != null ? _b : [\"paper\", \"deep-read\"]).join(\", \")).onChange(async (value) => {\n const tags = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n tags\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u7CBE\\u8BFB Prompt / Per-paper Deep Read prompt\").setDesc(\n \"\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u53D8\\u91CF: {{title}}, {{authors}}, {{published}}, {{arxiv_url}}, {{interest_hits}}, {{abstract}}, {{fulltext}}, {{language}}\"\n ).addTextArea((area) => {\n var _a3, _b;\n const plugin = this.plugin;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_b = (_a3 = plugin.settings.deepRead) == null ? void 0 : _a3.deepReadPromptTemplate) != null ? _b : \"\");\n area.inputEl.rows = 8;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n plugin.settings.deepRead = {\n ...plugin.settings.deepRead,\n deepReadPromptTemplate: val || void 0\n };\n await plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n let localPdfsSection = \"\";\n if ((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf) {\n const pdfsWithLocal = rankedPapers.filter((p) => p.links.localPdf);\n if (pdfsWithLocal.length > 0) {\n const lines = pdfsWithLocal.map(\n (p) => `- [${p.title}](${p.links.localPdf})`\n );\n localPdfsSection = `## \\u672C\\u5730 PDF / Local PDFs (${pdfsWithLocal.length} \\u7BC7)\n\n${lines.join(\"\\n\")}`;\n }\n }\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (localPdfsSection)\n sections.push(\"\", localPdfsSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = settings.scoringPromptTemplate || DEFAULT_SCORING_PROMPT;\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${batchIdx + 1}/${totalBatches}) ${batchPapers.length} \\u7BC7...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = (_t = settings.deepRead.deepReadPromptTemplate) != null ? _t : DEFAULT_DEEP_READ_PROMPT;\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const arxivUrl = `https://arxiv.org/abs/${baseId}`;\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n published: paper.published ? paper.published.slice(0, 10) : date,\n arxiv_url: arxivUrl,\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n try {\n const outputFolder = (_x = (_w = settings.deepRead) == null ? void 0 : _w.outputFolder) != null ? _x : \"PaperDaily/deep-read\";\n const fileTags = [\n ...(_z = (_y = settings.deepRead) == null ? void 0 : _y.tags) != null ? _z : [\"paper\", \"deep-read\"],\n ...((_A = paper.interestHits) != null ? _A : []).map((h) => h.replace(/\\s+/g, \"-\"))\n ];\n const safeId = baseId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n const paperFrontmatter = [\n \"---\",\n `type: deep-read`,\n `title: \"${paper.title.replace(/\"/g, '\\\\\"')}\"`,\n `date: ${date}`,\n `arxivId: ${baseId}`,\n `arxivUrl: ${arxivUrl}`,\n `authors: [${((_B = paper.authors) != null ? _B : []).slice(0, 5).map((a) => `\"${a.replace(/\"/g, '\\\\\"')}\"`).join(\", \")}]`,\n `published: ${paper.published ? paper.published.slice(0, 10) : date}`,\n `tags: [${fileTags.map((t) => `\"${t}\"`).join(\", \")}]`,\n ...paper.llmScore != null ? [`llmScore: ${paper.llmScore}`] : [],\n \"---\"\n ].join(\"\\n\");\n const paperMd = `${paperFrontmatter}\n\n# ${paper.title}\n\n${paper.deepReadAnalysis}\n`;\n await writer.writeNote(`${outputFolder}/${safeId}.md`, paperMd);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: wrote ${outputFolder}/${safeId}.md`);\n } catch (writeErr) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: failed to write per-paper file: ${String(writeErr)}`);\n }\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_D = (_C = settings.deepRead) == null ? void 0 : _C.enabled) != null ? _D : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const localPdfEntries = rankedPapers.filter((p) => p.links.localPdf).map((p) => `- [${p.title}](${p.links.localPdf})`);\n const localPdfsSection = localPdfEntries.length > 0 ? `## Local PDFs (${date})\n${localPdfEntries.join(\"\\n\")}` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: localPdfsSection,\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "513ba942c43d3a04a46185bf5b21559a41f215fd": {"t": 1785765938.869284, "n": 216245, "h": "61be1395d5d064ff", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n## Context\nPapers below (arXiv + HF) have been pre-ranked by: HuggingFace upvotes \\u2192 interest keyword weight.\n\n## Papers to analyze (pre-ranked, arXiv + HF):\n{{papers_json}}\n{{fulltext_section}}\n{{local_pdfs}}\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n---\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\". If full text is available above, draw from methods/experiments.\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} {links from the paper data}\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.`;\nvar DEFAULT_SCORING_PROMPT = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): {{interest_keywords}}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n{{papers_json}}`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Analyze the following paper concisely.\n\nTitle: {{title}}\nAuthors: {{authors}}\nInterest keyword hits: {{interest_hits}}\nAbstract: {{abstract}}\n\nFull paper HTML (read directly if you can access URLs): {{fulltext}}\n\nProvide a structured analysis with these sections:\n\n**\\u6838\\u5FC3\\u8D21\\u732E / Core Contribution** (2\\u20133 sentences): What exactly is built, proved, or demonstrated? Be specific with method/dataset names and key numbers.\n\n**\\u65B9\\u6CD5\\u4EAE\\u70B9 / Method Highlights** (2\\u20134 bullet points): Key technical choices, algorithmic novelty, or system design decisions.\n\n**\\u5B9E\\u9A8C\\u4E0E\\u7ED3\\u679C / Experiments & Results** (2\\u20133 sentences): Which benchmarks? Headline numbers vs baselines?\n\n**\\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway** (1\\u20132 sentences): What can a practitioner adopt from this work?\n\n**\\u5C40\\u9650\\u6027 / Limitations** (1\\u20132 sentences): Honest scope limitations or reproducibility concerns.\n\nKeep the total under 400 words. Be direct and opinionated. Output in {{language}}.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u5DE5\\u7A0B\\u7CBE\\u8BFB\", prompt: DEFAULT_DAILY_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 1024\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u5207\\u6362\\u5E76\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"{{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F\\uFF0C\\u683C\\u5F0F YYYY-MM-DD\"],\n [\"{{papers_json}}\", \"\\u6392\\u540D\\u540E\\u7684 arXiv + HF \\u8BBA\\u6587\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u6BCF\\u7BC7\\u542B id / title / abstract / interestHits / hfUpvotes / links \\u7B49\\u5B57\\u6BB5\\uFF0C\\u6700\\u591A 10 \\u7BC7\"],\n [\"{{hf_papers_json}}\", \"HuggingFace Daily Papers \\u539F\\u59CB\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u542B title / hfUpvotes / streakDays\\uFF0C\\u6700\\u591A 15 \\u6761\"],\n [\"{{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\\uFF1B\\u6BCF\\u7BC7\\u901A\\u8FC7 arxiv.org/html URL \\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\u539F\\u6587\\u5E76\\u751F\\u6210\\u5206\\u6790\\uFF1B\\u672A\\u5F00\\u542F Deep Read \\u65F6\\u4E3A\\u7A7A\"],\n [\"{{local_pdfs}}\", \"\\u5F53\\u65E5\\u5DF2\\u4E0B\\u8F7D\\u5230\\u672C\\u5730\\u7684 PDF \\u5217\\u8868\\uFF08Markdown \\u94FE\\u63A5\\uFF09\\uFF1B\\u672A\\u5F00\\u542F PDF \\u4E0B\\u8F7D\\u65F6\\u4E3A\\u7A7A\\u5B57\\u7B26\\u4E32\"],\n [\"{{interest_keywords}}\", \"\\u7528\\u6237\\u914D\\u7F6E\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u5217\\u8868\\uFF0C\\u542B\\u6743\\u91CD\\uFF0C\\u683C\\u5F0F\\u5982 rlhf(weight:5), agent(weight:5)\\uFF0C\\u4F9B\\u6A21\\u578B\\u53C2\\u8003\\u4F18\\u5148\\u7EA7\"],\n [\"{{language}}\", \"\\u8F93\\u51FA\\u8BED\\u8A00\\uFF0C\\u7531\\u8BBE\\u7F6E\\u4E2D'\\u8BED\\u8A00'\\u9009\\u9879\\u51B3\\u5B9A\\uFF0C\\u503C\\u4E3A Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n }\n if (!this.plugin.settings.activePromptId) {\n this.plugin.settings.activePromptId = this.plugin.settings.promptLibrary[0].id;\n }\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n tabBar.empty();\n const lib = this.plugin.settings.promptLibrary;\n for (const tpl of lib) {\n const isSelected = tpl.id === selectedId;\n const btn = tabBar.createEl(\"button\", { text: tpl.name });\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 14px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = () => {\n selectedId = tpl.id;\n this.plugin.settings.activePromptId = tpl.id;\n this.plugin.saveSettings();\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const lib2 = this.plugin.settings.promptLibrary;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib2.filter((t) => !t.builtin).length + 1}`,\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib2.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const lib = this.plugin.settings.promptLibrary;\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n this.plugin.settings.activePromptId = selectedId;\n promptTA.value = lib.find((t) => t.id === selectedId).prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = this.plugin.settings.promptLibrary.find((t) => t.id === selectedId)) != null ? _a2 : this.plugin.settings.promptLibrary[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u6279\\u91CF\\u8BC4\\u5206 Prompt / Scoring Prompt\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BC4\\u5206 Prompt / Scoring Prompt\").setDesc(\n '\\u6BCF\\u6279\\u8BBA\\u6587\\u7684\\u5FEB\\u901F\\u6253\\u5206 Prompt\\u3002\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\n\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A{{interest_keywords}}\\uFF08\\u5174\\u8DA3\\u5173\\u952E\\u8BCD+\\u6743\\u91CD\\uFF09\\uFF0C{{papers_json}}\\uFF08\\u672C\\u6279\\u8BBA\\u6587 JSON\\uFF09\\n\\u5FC5\\u987B\\u8981\\u6C42\\u6A21\\u578B\\u8FD4\\u56DE JSON \\u6570\\u7EC4\\uFF0C\\u683C\\u5F0F\\uFF1A[{\"id\":\"arxiv:...\",\"score\":1-10,\"reason\":\"...\",\"summary\":\"...\"}]'\n ).addTextArea((area) => {\n var _a3;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_a3 = this.plugin.settings.scoringPromptTemplate) != null ? _a3 : \"\");\n area.inputEl.rows = 10;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n this.plugin.settings.scoringPromptTemplate = val || void 0;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset to Default\").onClick(async () => {\n this.plugin.settings.scoringPromptTemplate = void 0;\n await this.plugin.saveSettings();\n this.display();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u7CBE\\u8BFB Prompt / Per-paper Deep Read prompt\").setDesc(\n \"\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u53D8\\u91CF: {{title}}, {{authors}}, {{directions}}, {{interest_hits}}, {{abstract}}, {{fulltext}}, {{language}}\"\n ).addTextArea((area) => {\n var _a3, _b;\n const plugin = this.plugin;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_b = (_a3 = plugin.settings.deepRead) == null ? void 0 : _a3.deepReadPromptTemplate) != null ? _b : \"\");\n area.inputEl.rows = 8;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n plugin.settings.deepRead = {\n ...plugin.settings.deepRead,\n deepReadPromptTemplate: val || void 0\n };\n await plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n let localPdfsSection = \"\";\n if ((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf) {\n const pdfsWithLocal = rankedPapers.filter((p) => p.links.localPdf);\n if (pdfsWithLocal.length > 0) {\n const lines = pdfsWithLocal.map(\n (p) => `- [${p.title}](${p.links.localPdf})`\n );\n localPdfsSection = `## \\u672C\\u5730 PDF / Local PDFs (${pdfsWithLocal.length} \\u7BC7)\n\n${lines.join(\"\\n\")}`;\n }\n }\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (localPdfsSection)\n sections.push(\"\", localPdfsSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n const BATCH_SIZE = 60;\n const totalBatches = Math.ceil(rankedPapers.length / BATCH_SIZE);\n const scoringTemplate = settings.scoringPromptTemplate || DEFAULT_SCORING_PROMPT;\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const llm = buildLLMProvider(settings);\n let totalScored = 0;\n for (let batchIdx = 0; batchIdx < totalBatches; batchIdx++) {\n const batchStart = batchIdx * BATCH_SIZE;\n const batchPapers = rankedPapers.slice(batchStart, batchStart + BATCH_SIZE);\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B (${batchIdx + 1}/${totalBatches}) ${batchPapers.length} \\u7BC7...`);\n const papersForScoring = batchPapers.map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const batchMaxTokens = Math.min(batchPapers.length * 150 + 256, 8192);\n const scoringPrompt = fillTemplate(scoringTemplate, {\n interest_keywords: kwStr,\n papers_json: JSON.stringify(papersForScoring)\n });\n try {\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: batchMaxTokens });\n if (result.usage)\n trackUsage(`Step 3b scoring batch ${batchIdx + 1}`, result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of batchPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n totalScored += matched;\n log(`Step 3b batch ${batchIdx + 1}/${totalBatches}: scored ${matched}/${batchPapers.length} (LLM returned ${scores.length})`);\n if (matched === 0 && scores.length > 0) {\n log(`Step 3b batch ${batchIdx + 1} WARNING: 0 matched \\u2014 ID mismatch? LLM=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper=\"${(_p = batchPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b batch ${batchIdx + 1}: could not parse JSON (response length=${result.text.length})`);\n }\n } catch (err) {\n log(`Step 3b batch ${batchIdx + 1} ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: done \\u2014 ${totalScored}/${rankedPapers.length} papers scored across ${totalBatches} batch(es), re-ranked`);\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = (_t = settings.deepRead.deepReadPromptTemplate) != null ? _t : DEFAULT_DEEP_READ_PROMPT;\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_x = (_w = settings.deepRead) == null ? void 0 : _w.enabled) != null ? _x : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const localPdfEntries = rankedPapers.filter((p) => p.links.localPdf).map((p) => `- [${p.title}](${p.links.localPdf})`);\n const localPdfsSection = localPdfEntries.length > 0 ? `## Local PDFs (${date})\n${localPdfEntries.join(\"\\n\")}` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: localPdfsSection,\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}, "911a6a75f8ea37787b6209f35118faa83defffb8": {"t": 1785765941.057699, "n": 213961, "h": "39b3cddbe3952b0f", "c": "/*\nTHIS IS A GENERATED/BUNDLED FILE BY ESBUILD\nif you want to view the source, please visit the github repository of this plugin\n*/\n\n\"use strict\";\nvar __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\n\n// src/main.ts\nvar main_exports = {};\n__export(main_exports, {\n default: () => PaperDailyPlugin\n});\nmodule.exports = __toCommonJS(main_exports);\nvar import_obsidian7 = require(\"obsidian\");\n\n// src/settings.ts\nvar import_obsidian = require(\"obsidian\");\nvar PROVIDER_PRESETS = {\n deepseek: {\n label: \"DeepSeek\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.deepseek.com/v1\",\n models: [\"deepseek-chat\", \"deepseek-reasoner\"],\n keyPlaceholder: \"sk-...\"\n },\n openai: {\n label: \"OpenAI\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n models: [\"gpt-4o-mini\", \"gpt-4o\", \"gpt-4-turbo\"],\n keyPlaceholder: \"sk-...\"\n },\n anthropic: {\n label: \"Claude\",\n provider: \"anthropic\",\n baseUrl: \"\",\n models: [\"claude-3-5-haiku-latest\", \"claude-3-5-sonnet-latest\", \"claude-opus-4-5\"],\n keyPlaceholder: \"sk-ant-...\"\n },\n glm: {\n label: \"GLM / \\u667A\\u8C31\",\n provider: \"openai_compatible\",\n baseUrl: \"https://open.bigmodel.cn/api/paas/v4\",\n models: [\"glm-4-flash\", \"glm-4-air\", \"glm-4\", \"glm-z1-flash\"],\n keyPlaceholder: \"your-zhipu-api-key\"\n },\n minimax: {\n label: \"MiniMax\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.minimax.chat/v1\",\n models: [\"MiniMax-Text-01\", \"abab6.5s-chat\", \"abab5.5-chat\"],\n keyPlaceholder: \"your-minimax-api-key\"\n },\n moonshot: {\n label: \"Moonshot / Kimi\",\n provider: \"openai_compatible\",\n baseUrl: \"https://api.moonshot.cn/v1\",\n models: [\"moonshot-v1-128k\", \"moonshot-v1-32k\", \"moonshot-v1-8k\"],\n keyPlaceholder: \"sk-...\"\n },\n qwen: {\n label: \"Qwen / \\u901A\\u4E49\",\n provider: \"openai_compatible\",\n baseUrl: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n models: [\"qwen-plus\", \"qwen-turbo\", \"qwen-max\", \"qwen-long\"],\n keyPlaceholder: \"sk-...\"\n },\n custom: {\n label: \"Custom\",\n provider: \"openai_compatible\",\n baseUrl: \"\",\n models: [],\n keyPlaceholder: \"your-api-key\"\n }\n};\nfunction detectPreset(baseUrl) {\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n if (key === \"custom\")\n continue;\n if (preset.baseUrl && baseUrl.startsWith(preset.baseUrl))\n return key;\n }\n return baseUrl ? \"custom\" : \"deepseek\";\n}\nvar DEFAULT_DAILY_PROMPT = `You are a senior AI/ML research analyst and critical peer reviewer. You combine deep engineering insight with academic rigor. Be direct and opinionated.\n\nToday: {{date}}\nOutput language: {{language}}\n\n## Context\nPapers below (arXiv + HF) have been pre-ranked by: HuggingFace upvotes \\u2192 interest keyword weight.\n\n## Papers to analyze (pre-ranked, arXiv + HF):\n{{papers_json}}\n{{fulltext_section}}\n{{local_pdfs}}\n## User's interest keywords (with weights, higher = more important):\n{{interest_keywords}}\n\n## HuggingFace Daily Papers (community picks, sorted by upvotes):\n{{hf_papers_json}}\n\n---\n\nGenerate the daily digest with the following sections:\n\n### \\u4ECA\\u65E5\\u8981\\u70B9 / Key Takeaways\n3\\u20135 punchy bullet points. What actually moved the needle today vs what is incremental noise? Note any papers appearing in both arXiv results and HF daily. Be direct.\n\n### \\u7CBE\\u9009\\u8BBA\\u6587 / Curated Papers\nFor **each paper** in the list, output exactly this structure:\n\n**[N]. {title}**\n- \\u2B50 \\u4EF7\\u503C\\u8BC4\\u7EA7: {\\u2605\\u2605\\u2605\\u2605\\u2605 to \\u2605\\u2606\\u2606\\u2606\\u2606} ({one-phrase reason})\n- \\u5173\\u952E\\u8BCD: {interest hits}\n- \\u{1F4A1} \\u6838\\u5FC3\\u8D21\\u732E: one sentence \\u2014 what exactly did they do / prove / build? Be specific with method names and key numbers.\n- \\u{1F52C} \\u65B9\\u6CD5\\u6838\\u5FC3: key technical novelty \\u2014 principled or ad hoc? any theoretical guarantees or assumptions worth noting?\n- \\u{1F4CA} \\u5B9E\\u9A8C\\u4E25\\u8C28\\u6027: are baselines fair and up-to-date? ablations sufficient? any obvious cherry-picking or missing controls?\n- \\u{1F527} \\u5DE5\\u7A0B\\u542F\\u793A: what can a practitioner adopt? Be concrete \\u2014 \"use X to achieve Y\", not \"this is interesting\". If full text is available above, draw from methods/experiments.\n- \\u26A0\\uFE0F \\u5C40\\u9650\\u6027 & \\u53EF\\u590D\\u73B0\\u6027: scope limitations + code availability + compute requirements. Can a grad student replicate this?\n- \\u{1F4DA} \\u5EFA\\u8BAE: {Skip | Read abstract | Skim methods | Read in full | Implement & test}\n- \\u{1F517} {links from the paper data}\n\nValue rating guide \\u2014 be calibrated, not generous:\n\\u2605\\u2605\\u2605\\u2605\\u2605 Breakthrough: likely to shift practice or become a citation anchor\n\\u2605\\u2605\\u2605\\u2605\\u2606 Strong: clear improvement, solid evaluation, worth reading in full\n\\u2605\\u2605\\u2605\\u2606\\u2606 Solid: incremental but honest; good for domain awareness\n\\u2605\\u2605\\u2606\\u2606\\u2606 Weak: narrow scope, questionable baselines, or limited novelty\n\\u2605\\u2606\\u2606\\u2606\\u2606 Skip: below standard, off-topic, or superseded\n\n### HF \\u793E\\u533A\\u4FE1\\u53F7 / HF Community Signal\nFrom the HuggingFace daily picks, list any papers NOT already covered above that are worth noting. One line each: title + why the community is upvoting it + your take on whether it lives up to the hype.\n\n### \\u4ECA\\u65E5\\u6279\\u6B21\\u8D28\\u91CF & \\u7ED3\\u8BED / Batch Quality & Closing\n2\\u20133 sentences: Is today a high-signal or low-signal day? What's the overall quality distribution? The single most important thing to keep an eye on from today's batch.\n\n---\nRules:\n- Do NOT hedge every sentence. State your assessment directly.\n- Call out benchmark overfitting, p-hacking, insufficient baselines, or vague claims explicitly.\n- If hfUpvotes is high but interest keyword relevance is low, note the discrepancy.\n- If a paper seems overhyped relative to its technical content, say so.\n- Keep engineering perspective front and center.\n- \\u5DE5\\u7A0B\\u542F\\u793A must be actionable \\u2014 not \"this is interesting\" but \"you can use X to achieve Y in your system\".\n- Recommendations must be specific \\u2014 no \"interesting direction\" hedging.`;\nvar DEFAULT_DEEP_READ_PROMPT = `You are a senior AI/ML research analyst. Analyze the following paper concisely.\n\nTitle: {{title}}\nAuthors: {{authors}}\nInterest keyword hits: {{interest_hits}}\nAbstract: {{abstract}}\n\nFull paper HTML (read directly if you can access URLs): {{fulltext}}\n\nProvide a structured analysis with these sections:\n\n**\\u6838\\u5FC3\\u8D21\\u732E / Core Contribution** (2\\u20133 sentences): What exactly is built, proved, or demonstrated? Be specific with method/dataset names and key numbers.\n\n**\\u65B9\\u6CD5\\u4EAE\\u70B9 / Method Highlights** (2\\u20134 bullet points): Key technical choices, algorithmic novelty, or system design decisions.\n\n**\\u5B9E\\u9A8C\\u4E0E\\u7ED3\\u679C / Experiments & Results** (2\\u20133 sentences): Which benchmarks? Headline numbers vs baselines?\n\n**\\u5DE5\\u7A0B\\u542F\\u793A / Engineering Takeaway** (1\\u20132 sentences): What can a practitioner adopt from this work?\n\n**\\u5C40\\u9650\\u6027 / Limitations** (1\\u20132 sentences): Honest scope limitations or reproducibility concerns.\n\nKeep the total under 400 words. Be direct and opinionated. Output in {{language}}.`;\nvar DEFAULT_PROMPT_LIBRARY = [\n { id: \"builtin_engineering\", name: \"\\u5DE5\\u7A0B\\u7CBE\\u8BFB\", prompt: DEFAULT_DAILY_PROMPT, builtin: true }\n];\nvar DEFAULT_SETTINGS = {\n categories: [\"cs.AI\", \"cs.LG\", \"cs.CL\"],\n // Matching is case-insensitive (keywords are lowercased before comparison)\n interestKeywords: [\n { keyword: \"rlhf\", weight: 5 },\n { keyword: \"agent\", weight: 5 },\n { keyword: \"kv cache\", weight: 4 },\n { keyword: \"speculative decoding\", weight: 4 },\n { keyword: \"moe\", weight: 4 },\n { keyword: \"inference serving\", weight: 4 },\n { keyword: \"reasoning\", weight: 3 },\n { keyword: \"post-training\", weight: 3 },\n { keyword: \"distillation\", weight: 3 },\n { keyword: \"quantization\", weight: 3 }\n ],\n fetchMode: \"all\",\n dedup: true,\n timeWindowHours: 72,\n llm: {\n provider: \"openai_compatible\",\n baseUrl: \"https://api.openai.com/v1\",\n apiKey: \"\",\n model: \"gpt-4o-mini\",\n temperature: 0.3,\n maxTokens: 4096,\n dailyPromptTemplate: DEFAULT_DAILY_PROMPT\n },\n rootFolder: \"PaperDaily\",\n language: \"zh\",\n includeAbstract: true,\n includePdfLink: true,\n schedule: {\n dailyTime: \"08:30\"\n },\n backfillMaxDays: 30,\n hfSource: {\n enabled: true,\n lookbackDays: 3,\n dedup: false\n },\n rssSource: {\n enabled: false,\n feeds: []\n },\n paperDownload: {\n savePdf: true\n },\n deepRead: {\n enabled: false,\n topN: 5,\n deepReadMaxTokens: 1024\n // deepReadPromptTemplate intentionally omitted → pipeline falls back to DEFAULT_DEEP_READ_PROMPT\n },\n promptLibrary: DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t })),\n activePromptId: \"builtin_engineering\"\n};\nvar PaperDailySettingTab = class extends import_obsidian.PluginSettingTab {\n constructor(app, plugin) {\n super(app, plugin);\n this.plugin = plugin;\n }\n display() {\n var _a2;\n const { containerEl } = this;\n containerEl.empty();\n containerEl.createEl(\"h1\", { text: \"Paper Daily \\u8BBE\\u7F6E / Settings\" });\n containerEl.createEl(\"h2\", { text: \"arXiv \\u8BBA\\u6587\\u6293\\u53D6 / Fetch\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u5206\\u7C7B / Categories\").setDesc(\"arXiv \\u5206\\u7C7B\\uFF0C\\u9017\\u53F7\\u5206\\u9694 | Comma-separated arXiv categories (e.g. cs.AI,cs.LG,cs.CL)\").addText((text) => text.setPlaceholder(\"cs.AI,cs.LG,cs.CL\").setValue(this.plugin.settings.categories.join(\",\")).onChange(async (value) => {\n this.plugin.settings.categories = value.split(\",\").map((s) => s.trim()).filter(Boolean);\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u62C9\\u53D6\\u65B9\\u5F0F / Fetch Mode\").setDesc(\n \"\\u5168\\u91CF\\u62C9\\u53D6\\uFF1A\\u6293\\u53D6\\u5206\\u7C7B\\u4E0B\\u6240\\u6709\\u8BBA\\u6587\\uFF08\\u7531 LLM \\u6253\\u5206\\u540E\\u6392\\u5E8F\\u5C55\\u793A\\uFF09\\n\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\uFF1A\\u53EA\\u4FDD\\u7559\\u547D\\u4E2D\\u81F3\\u5C11\\u4E00\\u4E2A\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u7684\\u8BBA\\u6587\\uFF0C\\u9002\\u5408\\u5173\\u952E\\u8BCD\\u8986\\u76D6\\u5168\\u9762\\u65F6\\u4F7F\\u7528\\u3002\\n\\nFetch all: retrieve all papers in the selected categories and let LLM scoring determine relevance.\\nInterest only: keep only papers matching at least one interest keyword \\u2014 best when your keyword list is comprehensive.\"\n ).addDropdown((drop) => {\n var _a3;\n return drop.addOption(\"all\", \"\\u5168\\u91CF\\u62C9\\u53D6 / Fetch All\").addOption(\"interest_only\", \"\\u4EC5\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Only\").setValue((_a3 = this.plugin.settings.fetchMode) != null ? _a3 : \"all\").onChange(async (value) => {\n this.plugin.settings.fetchMode = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u4FDD\\u5B58 PDF / Save PDF\").setDesc(\"\\u4E0B\\u8F7D\\u8BBA\\u6587 PDF \\u5E76\\u5B58\\u5165 Vault\\uFF08papers/pdf/\\u65E5\\u671F/\\uFF09\\uFF0C\\u5DF2\\u4E0B\\u8F7D\\u7684\\u6587\\u4EF6\\u81EA\\u52A8\\u8DF3\\u8FC7 | Download paper PDFs into the vault (papers/pdf/date/). Already-downloaded files are skipped.\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.paperDownload) == null ? void 0 : _a3.savePdf) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.paperDownload = { ...this.plugin.settings.paperDownload, savePdf: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u53BB\\u91CD / Dedup\").setDesc(\"\\u8DF3\\u8FC7\\u5DF2\\u5728\\u5F80\\u671F\\u65E5\\u62A5\\u4E2D\\u51FA\\u73B0\\u8FC7\\u7684\\u8BBA\\u6587\\uFF0C\\u907F\\u514D\\u91CD\\u590D\\u5C55\\u793A\\u3002\\u5173\\u95ED\\u540E\\u6BCF\\u6B21\\u8FD0\\u884C\\u90FD\\u4F1A\\u91CD\\u65B0\\u5904\\u7406\\u5168\\u90E8\\u62C9\\u53D6\\u7ED3\\u679C | Skip papers already shown in a previous daily report. Disable to reprocess all fetched papers every run.\").addToggle((toggle) => {\n var _a3;\n return toggle.setValue((_a3 = this.plugin.settings.dedup) != null ? _a3 : true).onChange(async (value) => {\n this.plugin.settings.dedup = value;\n await this.plugin.saveSettings();\n });\n }).addButton((btn) => btn.setButtonText(\"\\u6E05\\u7A7A\\u7F13\\u5B58 / Clear\").setWarning().onClick(async () => {\n await this.plugin.clearDedup();\n new import_obsidian.Notice(\"\\u53BB\\u91CD\\u7F13\\u5B58\\u5DF2\\u6E05\\u7A7A / Dedup cache cleared.\");\n }));\n new import_obsidian.Setting(containerEl).setName(\"HF \\u56DE\\u6EAF\\u5929\\u6570 / HF Lookback Days\").setDesc(\"huggingface.co/papers \\u65E0\\u5F53\\u65E5\\u6570\\u636E\\u65F6\\uFF08\\u5982\\u5468\\u672B\\uFF09\\uFF0C\\u5F80\\u524D\\u67E5\\u627E\\u6700\\u8FD1 N \\u5929\\u7684\\u7CBE\\u9009 | If today has no HF papers (e.g. weekend), look back up to N days\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(0, 7, 1).setValue((_b = (_a3 = this.plugin.settings.hfSource) == null ? void 0 : _a3.lookbackDays) != null ? _b : 3).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.hfSource = { ...this.plugin.settings.hfSource, lookbackDays: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u65F6\\u95F4\\u7A97\\u53E3\\uFF08\\u5C0F\\u65F6\\uFF09/ Time Window (hours)\").setDesc(\"\\u6293\\u53D6\\u8FC7\\u53BB N \\u5C0F\\u65F6\\u5185\\u53D1\\u5E03\\u6216\\u66F4\\u65B0\\u7684\\u8BBA\\u6587\\uFF0C\\u9ED8\\u8BA4 72 \\u5C0F\\u65F6\\u8986\\u76D6\\u5468\\u672B | Fetch papers published/updated within the past N hours. Default 72 covers weekends.\").addSlider((slider) => {\n var _a3;\n return slider.setLimits(24, 168, 24).setValue((_a3 = this.plugin.settings.timeWindowHours) != null ? _a3 : 72).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.timeWindowHours = value;\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5174\\u8DA3\\u5173\\u952E\\u8BCD / Interest Keywords\" });\n containerEl.createEl(\"p\", {\n text: \"\\u7528\\u4E8E\\u8BBA\\u6587\\u6253\\u5206\\u4E0E\\u9AD8\\u4EAE\\u663E\\u793A\\uFF0C\\u6743\\u91CD\\u8D8A\\u9AD8\\u6392\\u540D\\u8D8A\\u9760\\u524D\\u3002\\u5339\\u914D\\u4E0D\\u533A\\u5206\\u5927\\u5C0F\\u5199\\u3002\",\n cls: \"setting-item-description\"\n });\n const kwListEl = containerEl.createDiv();\n const renderKwList = () => {\n kwListEl.empty();\n const kws = this.plugin.settings.interestKeywords;\n kws.forEach((kw, i) => {\n new import_obsidian.Setting(kwListEl).addText((text) => text.setPlaceholder(\"keyword\").setValue(kw.keyword).onChange(async (val) => {\n kws[i].keyword = val.trim();\n await this.plugin.saveSettings();\n })).addSlider((slider) => slider.setLimits(1, 5, 1).setValue(kw.weight).setDynamicTooltip().onChange(async (val) => {\n kws[i].weight = val;\n await this.plugin.saveSettings();\n })).addExtraButton((btn) => btn.setIcon(\"trash\").setTooltip(\"Remove\").onClick(async () => {\n kws.splice(i, 1);\n await this.plugin.saveSettings();\n renderKwList();\n }));\n });\n };\n renderKwList();\n new import_obsidian.Setting(containerEl).addButton((btn) => btn.setButtonText(\"+ \\u6DFB\\u52A0\\u5173\\u952E\\u8BCD\").setCta().onClick(async () => {\n this.plugin.settings.interestKeywords.push({ keyword: \"\", weight: 3 });\n await this.plugin.saveSettings();\n renderKwList();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6A21\\u578B\\u914D\\u7F6E / LLM Provider\" });\n const presetWrap = containerEl.createDiv({ cls: \"paper-daily-preset-wrap\" });\n presetWrap.style.display = \"flex\";\n presetWrap.style.flexWrap = \"wrap\";\n presetWrap.style.gap = \"6px\";\n presetWrap.style.marginBottom = \"16px\";\n let activePreset = detectPreset(this.plugin.settings.llm.baseUrl);\n let baseUrlInput;\n let modelSelect;\n let customModelInput;\n let modelCustomRow;\n let apiKeyInput;\n const renderModelOptions = (presetKey) => {\n if (!modelSelect)\n return;\n const preset = PROVIDER_PRESETS[presetKey];\n modelSelect.empty();\n for (const m of preset.models) {\n const opt = modelSelect.createEl(\"option\", { text: m, value: m });\n if (m === this.plugin.settings.llm.model)\n opt.selected = true;\n }\n const customOpt = modelSelect.createEl(\"option\", { text: \"Other (custom)...\", value: \"__custom__\" });\n if (!preset.models.includes(this.plugin.settings.llm.model)) {\n customOpt.selected = true;\n if (modelCustomRow)\n modelCustomRow.style.display = \"\";\n if (customModelInput)\n customModelInput.value = this.plugin.settings.llm.model;\n } else {\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n };\n const applyPreset = async (presetKey) => {\n activePreset = presetKey;\n const preset = PROVIDER_PRESETS[presetKey];\n this.plugin.settings.llm.provider = preset.provider;\n if (preset.baseUrl) {\n this.plugin.settings.llm.baseUrl = preset.baseUrl;\n if (baseUrlInput)\n baseUrlInput.value = preset.baseUrl;\n }\n if (apiKeyInput)\n apiKeyInput.placeholder = preset.keyPlaceholder;\n renderModelOptions(presetKey);\n if (preset.models.length > 0 && !preset.models.includes(this.plugin.settings.llm.model)) {\n this.plugin.settings.llm.model = preset.models[0];\n if (modelSelect)\n modelSelect.value = preset.models[0];\n if (modelCustomRow)\n modelCustomRow.style.display = \"none\";\n }\n presetWrap.querySelectorAll(\".paper-daily-preset-btn\").forEach((b) => {\n const el = b;\n if (el.dataset.preset === presetKey) {\n el.style.opacity = \"1\";\n el.style.fontWeight = \"600\";\n el.style.borderColor = \"var(--interactive-accent)\";\n el.style.color = \"var(--interactive-accent)\";\n } else {\n el.style.opacity = \"0.6\";\n el.style.fontWeight = \"400\";\n el.style.borderColor = \"var(--background-modifier-border)\";\n el.style.color = \"var(--text-normal)\";\n }\n });\n await this.plugin.saveSettings();\n };\n for (const [key, preset] of Object.entries(PROVIDER_PRESETS)) {\n const btn = presetWrap.createEl(\"button\", {\n text: preset.label,\n cls: \"paper-daily-preset-btn\"\n });\n btn.dataset.preset = key;\n btn.style.padding = \"4px 12px\";\n btn.style.borderRadius = \"6px\";\n btn.style.border = \"1px solid var(--background-modifier-border)\";\n btn.style.cursor = \"pointer\";\n btn.style.fontSize = \"0.85em\";\n btn.style.background = \"var(--background-secondary)\";\n btn.style.transition = \"all 0.15s\";\n if (key === activePreset) {\n btn.style.opacity = \"1\";\n btn.style.fontWeight = \"600\";\n btn.style.borderColor = \"var(--interactive-accent)\";\n btn.style.color = \"var(--interactive-accent)\";\n } else {\n btn.style.opacity = \"0.6\";\n btn.style.color = \"var(--text-normal)\";\n }\n btn.addEventListener(\"click\", () => applyPreset(key));\n }\n new import_obsidian.Setting(containerEl).setName(\"\\u63A5\\u53E3\\u5730\\u5740 / Base URL\").setDesc(\"API \\u7AEF\\u70B9\\uFF0C\\u9009\\u62E9\\u9884\\u8BBE\\u540E\\u81EA\\u52A8\\u586B\\u5165 | API endpoint (auto-filled by preset; edit for custom deployments)\").addText((text) => {\n baseUrlInput = text.inputEl;\n text.setPlaceholder(\"https://api.openai.com/v1\").setValue(this.plugin.settings.llm.baseUrl).onChange(async (value) => {\n this.plugin.settings.llm.baseUrl = value;\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"API \\u5BC6\\u94A5 / API Key\").setDesc(\"\\u6240\\u9009\\u670D\\u52A1\\u5546\\u7684 API \\u5BC6\\u94A5 | Your API key for the selected provider\").addText((text) => {\n var _a3, _b;\n apiKeyInput = text.inputEl;\n text.inputEl.type = \"password\";\n text.inputEl.placeholder = (_b = (_a3 = PROVIDER_PRESETS[activePreset]) == null ? void 0 : _a3.keyPlaceholder) != null ? _b : \"sk-...\";\n text.inputEl.value = this.plugin.settings.llm.apiKey;\n text.inputEl.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.apiKey = text.inputEl.value;\n await this.plugin.saveSettings();\n });\n });\n const modelSetting = new import_obsidian.Setting(containerEl).setName(\"\\u6A21\\u578B / Model\").setDesc(\"\\u4ECE\\u9884\\u8BBE\\u4E2D\\u9009\\u62E9\\uFF0C\\u6216\\u9009 Other \\u624B\\u52A8\\u8F93\\u5165 | Select a preset model or choose Other to type a custom name\");\n modelSetting.controlEl.style.flexDirection = \"column\";\n modelSetting.controlEl.style.alignItems = \"flex-start\";\n modelSetting.controlEl.style.gap = \"6px\";\n modelSelect = modelSetting.controlEl.createEl(\"select\");\n modelSelect.style.width = \"100%\";\n modelSelect.style.padding = \"4px 6px\";\n modelSelect.style.borderRadius = \"4px\";\n modelSelect.style.border = \"1px solid var(--background-modifier-border)\";\n modelSelect.style.background = \"var(--background-primary)\";\n modelSelect.style.color = \"var(--text-normal)\";\n modelSelect.style.fontSize = \"0.9em\";\n modelCustomRow = modelSetting.controlEl.createDiv();\n modelCustomRow.style.width = \"100%\";\n modelCustomRow.style.display = \"none\";\n customModelInput = modelCustomRow.createEl(\"input\", { type: \"text\" });\n customModelInput.placeholder = \"Enter model name...\";\n customModelInput.style.width = \"100%\";\n customModelInput.style.padding = \"4px 6px\";\n customModelInput.style.borderRadius = \"4px\";\n customModelInput.style.border = \"1px solid var(--background-modifier-border)\";\n customModelInput.style.background = \"var(--background-primary)\";\n customModelInput.style.color = \"var(--text-normal)\";\n customModelInput.style.fontSize = \"0.9em\";\n customModelInput.addEventListener(\"input\", async () => {\n this.plugin.settings.llm.model = customModelInput.value;\n await this.plugin.saveSettings();\n });\n renderModelOptions(activePreset);\n modelSelect.addEventListener(\"change\", async () => {\n if (modelSelect.value === \"__custom__\") {\n modelCustomRow.style.display = \"\";\n customModelInput.focus();\n } else {\n modelCustomRow.style.display = \"none\";\n this.plugin.settings.llm.model = modelSelect.value;\n await this.plugin.saveSettings();\n }\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u6E29\\u5EA6 / Temperature\").setDesc(\"\\u6A21\\u578B\\u751F\\u6210\\u6E29\\u5EA6\\uFF080 = \\u786E\\u5B9A\\u6027\\uFF0C1 = \\u6700\\u5927\\u968F\\u673A\\uFF09| LLM temperature (0.0 = deterministic, 1.0 = most random)\").addSlider((slider) => slider.setLimits(0, 1, 0.05).setValue(this.plugin.settings.llm.temperature).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.temperature = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927 Token \\u6570 / Max Tokens\").setDesc(\"\\u6A21\\u578B\\u5355\\u6B21\\u54CD\\u5E94\\u7684\\u6700\\u5927 token \\u6570 | Maximum tokens for LLM response\").addSlider((slider) => slider.setLimits(512, 8192, 256).setValue(this.plugin.settings.llm.maxTokens).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.llm.maxTokens = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h3\", { text: \"Prompt \\u6A21\\u677F\\u5E93 / Prompt Library\" });\n {\n const desc = containerEl.createEl(\"div\", { cls: \"setting-item-description\" });\n desc.createEl(\"p\", { text: \"\\u70B9\\u51FB Tab \\u5207\\u6362\\u5E76\\u6FC0\\u6D3B\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u5360\\u4F4D\\u7B26\\uFF1A\" });\n const table = desc.createEl(\"table\");\n table.style.fontSize = \"11px\";\n table.style.borderCollapse = \"collapse\";\n table.style.width = \"100%\";\n const rows = [\n [\"{{date}}\", \"\\u5F53\\u65E5\\u65E5\\u671F\\uFF0C\\u683C\\u5F0F YYYY-MM-DD\"],\n [\"{{papers_json}}\", \"\\u6392\\u540D\\u540E\\u7684 arXiv + HF \\u8BBA\\u6587\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u6BCF\\u7BC7\\u542B id / title / abstract / interestHits / hfUpvotes / links \\u7B49\\u5B57\\u6BB5\\uFF0C\\u6700\\u591A 10 \\u7BC7\"],\n [\"{{hf_papers_json}}\", \"HuggingFace Daily Papers \\u539F\\u59CB\\u5217\\u8868\\uFF08JSON\\uFF09\\uFF0C\\u542B title / hfUpvotes / streakDays\\uFF0C\\u6700\\u591A 15 \\u6761\"],\n [\"{{fulltext_section}}\", \"Deep Read \\u7CBE\\u8BFB\\u7ED3\\u679C\\uFF08Markdown\\uFF09\\uFF1B\\u6BCF\\u7BC7\\u901A\\u8FC7 arxiv.org/html URL \\u8BA9\\u6A21\\u578B\\u76F4\\u63A5\\u8BFB\\u539F\\u6587\\u5E76\\u751F\\u6210\\u5206\\u6790\\uFF1B\\u672A\\u5F00\\u542F Deep Read \\u65F6\\u4E3A\\u7A7A\"],\n [\"{{local_pdfs}}\", \"\\u5F53\\u65E5\\u5DF2\\u4E0B\\u8F7D\\u5230\\u672C\\u5730\\u7684 PDF \\u5217\\u8868\\uFF08Markdown \\u94FE\\u63A5\\uFF09\\uFF1B\\u672A\\u5F00\\u542F PDF \\u4E0B\\u8F7D\\u65F6\\u4E3A\\u7A7A\\u5B57\\u7B26\\u4E32\"],\n [\"{{interest_keywords}}\", \"\\u7528\\u6237\\u914D\\u7F6E\\u7684\\u5174\\u8DA3\\u5173\\u952E\\u8BCD\\u5217\\u8868\\uFF0C\\u542B\\u6743\\u91CD\\uFF0C\\u683C\\u5F0F\\u5982 rlhf(weight:5), agent(weight:5)\\uFF0C\\u4F9B\\u6A21\\u578B\\u53C2\\u8003\\u4F18\\u5148\\u7EA7\"],\n [\"{{language}}\", \"\\u8F93\\u51FA\\u8BED\\u8A00\\uFF0C\\u7531\\u8BBE\\u7F6E\\u4E2D'\\u8BED\\u8A00'\\u9009\\u9879\\u51B3\\u5B9A\\uFF0C\\u503C\\u4E3A Chinese (\\u4E2D\\u6587) \\u6216 English\"]\n ];\n for (const [ph, explain] of rows) {\n const tr = table.createEl(\"tr\");\n const td1 = tr.createEl(\"td\");\n td1.style.padding = \"2px 8px 2px 0\";\n td1.style.whiteSpace = \"nowrap\";\n td1.style.fontFamily = \"monospace\";\n td1.style.color = \"var(--text-accent)\";\n td1.setText(ph);\n const td2 = tr.createEl(\"td\");\n td2.style.padding = \"2px 0\";\n td2.style.color = \"var(--text-muted)\";\n td2.setText(explain);\n }\n desc.style.marginBottom = \"10px\";\n if (!this.plugin.settings.promptLibrary || this.plugin.settings.promptLibrary.length === 0) {\n this.plugin.settings.promptLibrary = DEFAULT_PROMPT_LIBRARY.map((t) => ({ ...t }));\n this.plugin.settings.activePromptId = \"builtin_engineering\";\n }\n if (!this.plugin.settings.activePromptId) {\n this.plugin.settings.activePromptId = this.plugin.settings.promptLibrary[0].id;\n }\n let selectedId = this.plugin.settings.activePromptId;\n const tabBar = containerEl.createDiv();\n tabBar.style.cssText = \"display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px;align-items:center;\";\n const promptTA = containerEl.createEl(\"textarea\");\n promptTA.style.cssText = \"width:100%;height:300px;font-family:monospace;font-size:11px;padding:8px;resize:vertical;box-sizing:border-box;\";\n const actionsRow = containerEl.createDiv();\n actionsRow.style.cssText = \"display:flex;gap:8px;margin-top:8px;flex-wrap:wrap;align-items:center;\";\n const renderTabs = () => {\n tabBar.empty();\n const lib = this.plugin.settings.promptLibrary;\n for (const tpl of lib) {\n const isSelected = tpl.id === selectedId;\n const btn = tabBar.createEl(\"button\", { text: tpl.name });\n const accent = \"var(--interactive-accent)\";\n const border = \"var(--background-modifier-border)\";\n btn.style.cssText = [\n \"padding:5px 14px\",\n \"border-radius:5px\",\n \"cursor:pointer\",\n \"font-size:0.85em\",\n `border:2px solid ${isSelected ? accent : border}`,\n `background:${isSelected ? accent : \"var(--background-secondary)\"}`,\n `color:${isSelected ? \"var(--text-on-accent)\" : \"var(--text-normal)\"}`,\n \"font-weight:\" + (isSelected ? \"600\" : \"400\"),\n \"transition:all 0.1s\"\n ].join(\";\");\n btn.onclick = () => {\n selectedId = tpl.id;\n this.plugin.settings.activePromptId = tpl.id;\n this.plugin.saveSettings();\n promptTA.value = tpl.prompt;\n renderTabs();\n renderActions();\n };\n }\n const addBtn = tabBar.createEl(\"button\", { text: \"\\uFF0B \\u65B0\\u5EFA\" });\n addBtn.style.cssText = \"padding:5px 12px;border-radius:5px;cursor:pointer;font-size:0.85em;border:2px dashed var(--background-modifier-border);background:transparent;color:var(--text-muted);\";\n addBtn.onclick = async () => {\n const lib2 = this.plugin.settings.promptLibrary;\n const newTpl = {\n id: `custom_${Date.now()}`,\n name: `\\u81EA\\u5B9A\\u4E49 ${lib2.filter((t) => !t.builtin).length + 1}`,\n prompt: DEFAULT_DAILY_PROMPT\n };\n lib2.push(newTpl);\n selectedId = newTpl.id;\n this.plugin.settings.activePromptId = newTpl.id;\n await this.plugin.saveSettings();\n promptTA.value = newTpl.prompt;\n renderTabs();\n renderActions();\n };\n };\n const renderActions = () => {\n actionsRow.empty();\n const lib = this.plugin.settings.promptLibrary;\n const tpl = lib.find((t) => t.id === selectedId);\n if (!tpl)\n return;\n const saveBtn = actionsRow.createEl(\"button\", { text: \"\\u4FDD\\u5B58 / Save\" });\n saveBtn.style.cssText = \"padding:4px 16px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--interactive-accent);color:var(--text-on-accent);border:none;font-weight:600;\";\n saveBtn.onclick = async () => {\n tpl.prompt = promptTA.value;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(`\\u6A21\\u677F\\u5DF2\\u4FDD\\u5B58\\uFF1A${tpl.name}`);\n };\n const renameBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u547D\\u540D / Rename\" });\n renameBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-normal);\";\n renameBtn.onclick = async () => {\n const newName = prompt(\"\\u65B0\\u540D\\u79F0 / New name:\", tpl.name);\n if (newName == null ? void 0 : newName.trim()) {\n tpl.name = newName.trim();\n await this.plugin.saveSettings();\n renderTabs();\n }\n };\n if (tpl.builtin) {\n const resetBtn = actionsRow.createEl(\"button\", { text: \"\\u91CD\\u7F6E\\u9ED8\\u8BA4 / Reset\" });\n resetBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--background-modifier-border);color:var(--text-muted);\";\n resetBtn.onclick = async () => {\n const def = DEFAULT_PROMPT_LIBRARY.find((d) => d.id === tpl.id);\n if (def) {\n tpl.prompt = def.prompt;\n promptTA.value = tpl.prompt;\n await this.plugin.saveSettings();\n new import_obsidian.Notice(\"\\u5DF2\\u91CD\\u7F6E\\u4E3A\\u9ED8\\u8BA4 / Reset to default.\");\n }\n };\n }\n if (!tpl.builtin && lib.length > 1) {\n const delBtn = actionsRow.createEl(\"button\", { text: \"\\u5220\\u9664 / Delete\" });\n delBtn.style.cssText = \"padding:4px 14px;border-radius:4px;cursor:pointer;font-size:0.85em;background:var(--background-secondary);border:1px solid var(--text-error,#cc4444);color:var(--text-error,#cc4444);\";\n delBtn.onclick = async () => {\n const idx = lib.findIndex((t) => t.id === selectedId);\n lib.splice(idx, 1);\n selectedId = lib[Math.max(0, idx - 1)].id;\n this.plugin.settings.activePromptId = selectedId;\n promptTA.value = lib.find((t) => t.id === selectedId).prompt;\n await this.plugin.saveSettings();\n renderTabs();\n renderActions();\n };\n }\n };\n const initTpl = (_a2 = this.plugin.settings.promptLibrary.find((t) => t.id === selectedId)) != null ? _a2 : this.plugin.settings.promptLibrary[0];\n promptTA.value = initTpl.prompt;\n renderTabs();\n renderActions();\n }\n containerEl.createEl(\"h2\", { text: \"\\u8F93\\u51FA\\u683C\\u5F0F / Output\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6839\\u76EE\\u5F55 / Root Folder\").setDesc(\"Vault \\u5185\\u6240\\u6709 Paper Daily \\u6587\\u4EF6\\u7684\\u5B58\\u653E\\u76EE\\u5F55 | Folder inside vault where all Paper Daily files are written\").addText((text) => text.setPlaceholder(\"PaperDaily\").setValue(this.plugin.settings.rootFolder).onChange(async (value) => {\n this.plugin.settings.rootFolder = value || \"PaperDaily\";\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u8F93\\u51FA\\u8BED\\u8A00 / Language\").setDesc(\"AI \\u751F\\u6210\\u5185\\u5BB9\\u7684\\u8BED\\u8A00 | Output language for AI-generated content\").addDropdown((drop) => drop.addOption(\"zh\", \"\\u4E2D\\u6587 (Chinese)\").addOption(\"en\", \"English\").setValue(this.plugin.settings.language).onChange(async (value) => {\n this.plugin.settings.language = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B\\u6458\\u8981 / Include Abstract\").setDesc(\"\\u5728\\u539F\\u59CB\\u8BBA\\u6587\\u5217\\u8868\\u4E2D\\u663E\\u793A\\u6458\\u8981 | Include paper abstracts in the raw papers list\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includeAbstract).onChange(async (value) => {\n this.plugin.settings.includeAbstract = value;\n await this.plugin.saveSettings();\n }));\n new import_obsidian.Setting(containerEl).setName(\"\\u5305\\u542B PDF \\u94FE\\u63A5 / Include PDF Links\").setDesc(\"\\u5728\\u8F93\\u51FA Markdown \\u4E2D\\u5305\\u542B PDF \\u94FE\\u63A5 | Include PDF links in output markdown\").addToggle((toggle) => toggle.setValue(this.plugin.settings.includePdfLink).onChange(async (value) => {\n this.plugin.settings.includePdfLink = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u5B9A\\u65F6\\u4EFB\\u52A1 / Scheduling\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u65F6\\u95F4 / Daily Fetch Time\").setDesc(\"\\u6BCF\\u5929\\u81EA\\u52A8\\u8FD0\\u884C\\u7684\\u65F6\\u95F4\\uFF0824 \\u5C0F\\u65F6\\u5236 HH:MM\\uFF09| Time to run daily fetch (HH:MM, 24-hour)\").addText((text) => text.setPlaceholder(\"08:30\").setValue(this.plugin.settings.schedule.dailyTime).onChange(async (value) => {\n this.plugin.settings.schedule.dailyTime = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"h2\", { text: \"\\u6D4B\\u8BD5 / Test\" });\n const testStatusEl = containerEl.createEl(\"pre\", { text: \"\" });\n testStatusEl.style.color = \"var(--text-muted)\";\n testStatusEl.style.fontSize = \"0.82em\";\n testStatusEl.style.whiteSpace = \"pre-wrap\";\n testStatusEl.style.wordBreak = \"break-all\";\n testStatusEl.style.background = \"var(--background-secondary)\";\n testStatusEl.style.padding = \"8px 10px\";\n testStatusEl.style.borderRadius = \"6px\";\n testStatusEl.style.minHeight = \"1.8em\";\n testStatusEl.style.display = \"none\";\n const setStatus = (text, color = \"var(--text-muted)\") => {\n testStatusEl.style.display = \"\";\n testStatusEl.style.color = color;\n testStatusEl.setText(text);\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u7ACB\\u5373\\u8FD0\\u884C\\u6BCF\\u65E5\\u62A5\\u544A / Run Daily Report Now\").setDesc(\"\\u5B8C\\u6574\\u6D41\\u7A0B\\uFF1A\\u6293\\u53D6 + AI \\u6458\\u8981 + \\u5199\\u5165 inbox/\\uFF08\\u8BF7\\u5148\\u786E\\u8BA4 API Key \\u548C\\u914D\\u7F6E\\u6B63\\u786E\\uFF09| Full pipeline: fetch + AI digest + write to inbox/. Verify your API key first.\").addButton((btn) => {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setCta().onClick(async () => {\n btn.setButtonText(\"Running...\").setDisabled(true);\n setStatus(\"\\u542F\\u52A8\\u4E2D...\");\n try {\n await this.plugin.runDaily((msg) => setStatus(msg));\n setStatus(\"\\u2713 \\u5B8C\\u6210\\uFF01\\u8BF7\\u67E5\\u770B PaperDaily/inbox/ \\u4E2D\\u4ECA\\u5929\\u7684\\u6587\\u4EF6 / Done! Check PaperDaily/inbox/ for today's file.\", \"var(--color-green)\");\n } catch (err) {\n setStatus(`\\u2717 Error: ${String(err)}`, \"var(--color-red)\");\n } finally {\n btn.setButtonText(\"\\u25B6 \\u7ACB\\u5373\\u8FD0\\u884C / Run Daily Now\").setDisabled(false);\n }\n });\n });\n const rssHeader = containerEl.createEl(\"h2\");\n rssHeader.appendText(\"RSS \\u8BA2\\u9605\\u6E90 / RSS Sources \");\n rssHeader.createEl(\"span\", { text: \"beta\", cls: \"paper-daily-badge-beta\" });\n containerEl.createEl(\"p\", {\n text: \"\\u8BA2\\u9605\\u81EA\\u5B9A\\u4E49 RSS/Atom \\u6E90\\uFF08\\u5982 Semantic Scholar \\u63D0\\u9192\\u3001\\u671F\\u520A\\u8BA2\\u9605\\u7B49\\uFF09\\u3002Feed \\u89E3\\u6790\\u529F\\u80FD\\u5C1A\\u672A\\u6FC0\\u6D3B\\uFF0C\\u53EF\\u63D0\\u524D\\u914D\\u7F6E URL\\uFF0C\\u540E\\u7EED\\u7248\\u672C\\u5C06\\u652F\\u6301 | Subscribe to custom RSS/Atom feeds. Feed parsing is not yet active \\u2014 configure URLs now and they will be fetched in a future update.\",\n cls: \"setting-item-description\"\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F RSS \\u6E90 / Enable RSS source\").setDesc(\"\\uFF08Beta\\uFF09\\u5F00\\u542F\\u540E\\u5C06\\u5728\\u53EF\\u7528\\u65F6\\u5305\\u542B RSS \\u8BA2\\u9605\\u5185\\u5BB9 | (Beta) Toggle on to include RSS feeds when available\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.enabled) != null ? _b : false).setDisabled(true).onChange(async (value) => {\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, enabled: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(containerEl).setName(\"\\u8BA2\\u9605\\u5730\\u5740 / Feed URLs\").setDesc(\"\\u6BCF\\u884C\\u4E00\\u4E2A RSS/Atom URL\\uFF0CBeta \\u529F\\u80FD\\u6FC0\\u6D3B\\u540E\\u5C06\\u81EA\\u52A8\\u89E3\\u6790 | One RSS/Atom URL per line. Will be parsed when beta feature activates.\").addTextArea((area) => {\n var _a3, _b;\n area.setPlaceholder(\"https://export.arxiv.org/rss/cs.AI\\nhttps://example.com/feed.xml\");\n area.setValue(((_b = (_a3 = this.plugin.settings.rssSource) == null ? void 0 : _a3.feeds) != null ? _b : []).join(\"\\n\"));\n area.inputEl.rows = 4;\n area.inputEl.addEventListener(\"input\", async () => {\n const feeds = area.inputEl.value.split(\"\\n\").map((s) => s.trim()).filter(Boolean);\n this.plugin.settings.rssSource = { ...this.plugin.settings.rssSource, feeds };\n await this.plugin.saveSettings();\n });\n });\n containerEl.createEl(\"h2\", { text: \"\\u5168\\u6587\\u7CBE\\u8BFB / Deep Read\" });\n const drSubContainer = containerEl.createDiv();\n const refreshDrSub = () => {\n var _a3;\n drSubContainer.style.display = ((_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) ? \"\" : \"none\";\n };\n new import_obsidian.Setting(containerEl).setName(\"\\u5F00\\u542F\\u7CBE\\u8BFB / Enable Deep Read\").setDesc(\"\\u6293\\u53D6\\u6392\\u540D\\u6700\\u9AD8\\u7684 N \\u7BC7\\u8BBA\\u6587\\u7684\\u5168\\u6587\\uFF08arxiv.org/html\\uFF09\\uFF0C\\u6CE8\\u5165 LLM prompt\\uFF0C\\u8BA9\\u6A21\\u578B\\u505A\\u66F4\\u6DF1\\u5EA6\\u7684\\u9010\\u7BC7\\u5206\\u6790 | Fetch full paper text and inject into the digest prompt for richer per-paper analysis\").addToggle((toggle) => {\n var _a3, _b;\n return toggle.setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.enabled) != null ? _b : false).onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, enabled: value };\n await this.plugin.saveSettings();\n refreshDrSub();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u7CBE\\u8BFB\\u7BC7\\u6570 / Papers to fetch\").setDesc(\"\\u6BCF\\u65E5\\u6293\\u53D6\\u5168\\u6587\\u7684\\u6700\\u9AD8\\u5206\\u8BBA\\u6587\\u7BC7\\u6570\\uFF08\\u5EFA\\u8BAE 3\\u20135\\uFF0C\\u8D8A\\u591A prompt \\u8D8A\\u957F\\uFF09| Number of top papers to fetch full text for\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(1, 10, 1).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.topN) != null ? _b : 5).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = { ...this.plugin.settings.deepRead, topN: value };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u5206\\u6790 Token \\u4E0A\\u9650 / Max tokens per paper\").setDesc(\"Deep Read \\u6BCF\\u7BC7\\u8BBA\\u6587 LLM \\u8C03\\u7528\\u7684\\u8F93\\u51FA token \\u4E0A\\u9650\\uFF08\\u9ED8\\u8BA4 1024\\uFF0C\\u5EFA\\u8BAE 512\\u20132048\\uFF09\").addSlider((slider) => {\n var _a3, _b;\n return slider.setLimits(256, 4096, 128).setValue((_b = (_a3 = this.plugin.settings.deepRead) == null ? void 0 : _a3.deepReadMaxTokens) != null ? _b : 1024).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.deepRead = {\n ...this.plugin.settings.deepRead,\n deepReadMaxTokens: value\n };\n await this.plugin.saveSettings();\n });\n });\n new import_obsidian.Setting(drSubContainer).setName(\"\\u6BCF\\u7BC7\\u7CBE\\u8BFB Prompt / Per-paper Deep Read prompt\").setDesc(\n \"\\u7559\\u7A7A\\u4F7F\\u7528\\u9ED8\\u8BA4\\u6A21\\u677F\\u3002\\u53EF\\u7528\\u53D8\\u91CF: {{title}}, {{authors}}, {{directions}}, {{interest_hits}}, {{abstract}}, {{fulltext}}, {{language}}\"\n ).addTextArea((area) => {\n var _a3, _b;\n const plugin = this.plugin;\n area.setPlaceholder(\"(leave blank for default)\");\n area.setValue((_b = (_a3 = plugin.settings.deepRead) == null ? void 0 : _a3.deepReadPromptTemplate) != null ? _b : \"\");\n area.inputEl.rows = 8;\n area.inputEl.style.width = \"100%\";\n area.inputEl.style.fontFamily = \"monospace\";\n area.inputEl.style.fontSize = \"0.85em\";\n area.inputEl.addEventListener(\"input\", async () => {\n const val = area.inputEl.value.trim();\n plugin.settings.deepRead = {\n ...plugin.settings.deepRead,\n deepReadPromptTemplate: val || void 0\n };\n await plugin.saveSettings();\n });\n });\n refreshDrSub();\n containerEl.createEl(\"h2\", { text: \"\\u5386\\u53F2\\u56DE\\u586B / Backfill\" });\n new import_obsidian.Setting(containerEl).setName(\"\\u6700\\u5927\\u56DE\\u586B\\u5929\\u6570 / Max Backfill Days\").setDesc(\"\\u5355\\u6B21\\u56DE\\u586B\\u5141\\u8BB8\\u7684\\u6700\\u5927\\u5929\\u6570\\u8303\\u56F4\\uFF08\\u5B89\\u5168\\u4E0A\\u9650\\uFF09| Maximum number of days allowed in a backfill range (guardrail)\").addSlider((slider) => slider.setLimits(1, 90, 1).setValue(this.plugin.settings.backfillMaxDays).setDynamicTooltip().onChange(async (value) => {\n this.plugin.settings.backfillMaxDays = value;\n await this.plugin.saveSettings();\n }));\n containerEl.createEl(\"hr\");\n const contactDiv = containerEl.createDiv({ cls: \"paper-daily-contact\" });\n contactDiv.style.textAlign = \"center\";\n contactDiv.style.padding = \"20px 0 12px\";\n contactDiv.style.color = \"var(--text-muted)\";\n contactDiv.style.fontSize = \"0.88em\";\n contactDiv.style.lineHeight = \"1.8\";\n contactDiv.createEl(\"p\", {\n text: \"\\u{1F916} Paper Daily \\u2014 Built for the AI research community\"\n }).style.marginBottom = \"4px\";\n const emailLine = contactDiv.createEl(\"p\");\n emailLine.style.marginBottom = \"0\";\n emailLine.appendText(\"\\u{1F4EC} \\u8054\\u7CFB\\u4F5C\\u8005 / Contact me: \");\n const emailLink = emailLine.createEl(\"a\", {\n text: \"astra.jwt@gmail.com\",\n href: \"mailto:astra.jwt@gmail.com\"\n });\n emailLink.style.color = \"var(--interactive-accent)\";\n emailLink.style.textDecoration = \"none\";\n }\n};\n\n// src/storage/vaultWriter.ts\nvar import_obsidian2 = require(\"obsidian\");\nvar VaultWriter = class {\n constructor(app) {\n this.app = app;\n }\n async ensureFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (!existing) {\n await this.app.vault.createFolder(normalized);\n }\n }\n async ensureFolderForFile(filePath) {\n const parts = (0, import_obsidian2.normalizePath)(filePath).split(\"/\");\n parts.pop();\n if (parts.length > 0) {\n await this.ensureFolder(parts.join(\"/\"));\n }\n }\n async writeNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n await this.app.vault.modify(existing, content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async readNote(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n if (file instanceof import_obsidian2.TFile) {\n return await this.app.vault.read(file);\n }\n return null;\n }\n async appendToNote(filePath, content) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n await this.ensureFolderForFile(normalized);\n const existing = this.app.vault.getAbstractFileByPath(normalized);\n if (existing instanceof import_obsidian2.TFile) {\n const current = await this.app.vault.read(existing);\n await this.app.vault.modify(existing, current + content);\n } else {\n await this.app.vault.create(normalized, content);\n }\n }\n async fileExists(filePath) {\n const normalized = (0, import_obsidian2.normalizePath)(filePath);\n const file = this.app.vault.getAbstractFileByPath(normalized);\n return file instanceof import_obsidian2.TFile;\n }\n async listFolder(folderPath) {\n const normalized = (0, import_obsidian2.normalizePath)(folderPath);\n const folder = this.app.vault.getAbstractFileByPath(normalized);\n if (folder instanceof import_obsidian2.TFolder) {\n return folder.children.filter((f) => f instanceof import_obsidian2.TFile).map((f) => f.name);\n }\n return [];\n }\n};\n\n// src/storage/stateStore.ts\nvar StateStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.path = `${rootFolder}/cache/state.json`;\n this.state = {\n lastDailyRun: \"\",\n lastError: null\n };\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.state = JSON.parse(content);\n } catch (e) {\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.state, null, 2));\n }\n get() {\n return { ...this.state };\n }\n async setLastDailyRun(iso) {\n this.state.lastDailyRun = iso;\n await this.save();\n }\n async setLastError(stage, message) {\n this.state.lastError = { time: new Date().toISOString(), stage, message };\n await this.save();\n }\n async clearLastError() {\n this.state.lastError = null;\n await this.save();\n }\n};\n\n// src/storage/dedupStore.ts\nvar DedupStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/seen_ids.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n hasId(id) {\n return id in this.map;\n }\n async markSeen(id, date) {\n if (!this.map[id]) {\n this.map[id] = date;\n }\n }\n async markSeenBatch(ids, date) {\n for (const id of ids) {\n await this.markSeen(id, date);\n }\n await this.save();\n }\n // Remove entries older than keepDays to limit growth\n async prune(keepDays = 90) {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n const cutoffStr = cutoff.toISOString().slice(0, 10);\n for (const [id, date] of Object.entries(this.map)) {\n if (date < cutoffStr) {\n delete this.map[id];\n }\n }\n await this.save();\n }\n async clear() {\n this.map = {};\n await this.save();\n }\n size() {\n return Object.keys(this.map).length;\n }\n getMap() {\n return { ...this.map };\n }\n};\n\n// src/storage/snapshotStore.ts\nvar SnapshotStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.rootFolder = rootFolder;\n }\n snapshotPath(date) {\n return `${this.rootFolder}/papers/${date}.json`;\n }\n async writeSnapshot(date, papers, error) {\n const snapshot = {\n date,\n papers,\n fetchedAt: new Date().toISOString(),\n error\n };\n await this.writer.writeNote(\n this.snapshotPath(date),\n JSON.stringify(snapshot, null, 2)\n );\n }\n async readSnapshot(date) {\n const content = await this.writer.readNote(this.snapshotPath(date));\n if (!content)\n return null;\n try {\n return JSON.parse(content);\n } catch (e) {\n return null;\n }\n }\n async listSnapshotDates() {\n const files = await this.writer.listFolder(`${this.rootFolder}/papers`);\n return files.filter((f) => f.endsWith(\".json\")).map((f) => f.replace(\".json\", \"\")).sort();\n }\n async readSnapshotsForRange(startDate, endDate) {\n const dates = await this.listSnapshotDates();\n const filtered = dates.filter((d) => d >= startDate && d <= endDate);\n const results = [];\n for (const d of filtered) {\n const snap = await this.readSnapshot(d);\n if (snap)\n results.push(snap);\n }\n return results;\n }\n};\n\n// src/storage/hfTrackStore.ts\nvar HFTrackStore = class {\n constructor(writer, rootFolder) {\n this.writer = writer;\n this.map = {};\n this.path = `${rootFolder}/cache/hf_track.json`;\n }\n async load() {\n const content = await this.writer.readNote(this.path);\n if (content) {\n try {\n this.map = JSON.parse(content);\n } catch (e) {\n this.map = {};\n }\n }\n }\n async save() {\n await this.writer.writeNote(this.path, JSON.stringify(this.map, null, 2));\n }\n // Record that a paper appeared on HF on this date. Returns updated count.\n track(id, title, date) {\n const existing = this.map[id];\n if (existing) {\n if (existing.lastSeen === date)\n return existing.count;\n existing.lastSeen = date;\n existing.count += 1;\n return existing.count;\n }\n this.map[id] = { title, firstSeen: date, lastSeen: date, count: 1 };\n return 1;\n }\n getEntry(id) {\n return this.map[id];\n }\n // Was this paper seen before this date?\n seenBefore(id, date) {\n const e = this.map[id];\n return !!e && e.firstSeen < date;\n }\n};\n\n// src/sources/arxivSource.ts\nvar import_obsidian3 = require(\"obsidian\");\nvar ArxivSource = class {\n constructor() {\n this.name = \"arxiv\";\n this.enabled = true;\n }\n buildQuery(categories, keywords) {\n const catParts = categories.map((c) => `cat:${c}`);\n const catClause = catParts.length > 0 ? `(${catParts.join(\" OR \")})` : \"\";\n if (keywords.length === 0) {\n return catClause || \"all:*\";\n }\n const kwParts = keywords.map((k) => `all:\"${k}\"`);\n const kwClause = `(${kwParts.join(\" OR \")})`;\n return catClause ? `(${catClause}) AND ${kwClause}` : kwClause;\n }\n buildUrl(params, maxResults) {\n const query = this.buildQuery(params.categories, params.keywords);\n const encoded = encodeURIComponent(query);\n const sortOrder = \"descending\";\n return `https://export.arxiv.org/api/query?search_query=${encoded}&max_results=${maxResults}&sortBy=${params.sortBy}&sortOrder=${sortOrder}`;\n }\n parseAtomEntry(entry) {\n var _a2;\n const getText = (tag) => {\n var _a3, _b;\n const el = entry.querySelector(tag);\n return el ? (_b = (_a3 = el.textContent) == null ? void 0 : _a3.trim()) != null ? _b : \"\" : \"\";\n };\n const rawId = getText(\"id\");\n if (!rawId)\n return null;\n const arxivIdMatch = rawId.match(/arxiv\\.org\\/abs\\/([^v]+)(v\\d+)?/i);\n const arxivId = arxivIdMatch ? `arxiv:${arxivIdMatch[1]}${(_a2 = arxivIdMatch[2]) != null ? _a2 : \"\"}`.toLowerCase() : `arxiv:${rawId}`;\n const title = getText(\"title\").replace(/\\s+/g, \" \");\n const abstract = getText(\"summary\").replace(/\\s+/g, \" \");\n const published = getText(\"published\");\n const updated = getText(\"updated\");\n const authors = [];\n entry.querySelectorAll(\"author name\").forEach((el) => {\n var _a3;\n const name = (_a3 = el.textContent) == null ? void 0 : _a3.trim();\n if (name)\n authors.push(name);\n });\n const categories = [];\n entry.querySelectorAll(\"category\").forEach((el) => {\n const term = el.getAttribute(\"term\");\n if (term)\n categories.push(term);\n });\n let htmlLink = \"\";\n let pdfLink = \"\";\n entry.querySelectorAll(\"link\").forEach((el) => {\n var _a3, _b;\n const rel = el.getAttribute(\"rel\");\n const href = (_a3 = el.getAttribute(\"href\")) != null ? _a3 : \"\";\n const type = (_b = el.getAttribute(\"type\")) != null ? _b : \"\";\n if (rel === \"alternate\" || type === \"text/html\")\n htmlLink = href;\n if (type === \"application/pdf\" || href.includes(\"/pdf/\"))\n pdfLink = href;\n });\n return {\n id: arxivId,\n title,\n abstract,\n authors,\n categories,\n published,\n updated,\n links: { html: htmlLink || void 0, pdf: pdfLink || void 0 },\n source: \"arxiv\"\n };\n }\n filterByWindow(papers, windowStart, windowEnd) {\n return papers.filter((p) => {\n const dateStr = p.published || p.updated;\n if (!dateStr)\n return false;\n const d = new Date(dateStr);\n return d >= windowStart && d <= windowEnd;\n });\n }\n async fetch(params) {\n const maxResults = params.maxResults * 3;\n const url = this.buildUrl(params, maxResults);\n const delays = [5e3, 15e3, 3e4];\n let lastErr;\n for (let attempt = 0; attempt <= delays.length; attempt++) {\n if (attempt > 0) {\n const wait = delays[attempt - 1];\n console.log(`[PaperDaily] arXiv 429, retrying in ${wait / 1e3}s (attempt ${attempt}/${delays.length})...`);\n await new Promise((r) => setTimeout(r, wait));\n }\n try {\n const response = await (0, import_obsidian3.requestUrl)({ url, method: \"GET\" });\n const xmlText = response.text;\n const parser = new DOMParser();\n const doc = parser.parseFromString(xmlText, \"application/xml\");\n const parseError = doc.querySelector(\"parsererror\");\n if (parseError) {\n throw new Error(`arXiv XML parse error: ${parseError.textContent}`);\n }\n const entries = Array.from(doc.querySelectorAll(\"entry\"));\n const papers = [];\n for (const entry of entries) {\n const paper = this.parseAtomEntry(entry);\n if (paper)\n papers.push(paper);\n }\n return this.filterByWindow(papers, params.windowStart, params.windowEnd);\n } catch (err) {\n const msg = String(err);\n if (msg.includes(\"429\") && attempt < delays.length) {\n lastErr = err;\n continue;\n }\n throw err;\n }\n }\n throw lastErr;\n }\n};\n\n// src/sources/hfSource.ts\nvar import_obsidian4 = require(\"obsidian\");\nvar HFSource = class {\n constructor() {\n this.name = \"huggingface\";\n this.enabled = true;\n }\n // Fetch HF daily papers for a given date (YYYY-MM-DD).\n // Returns Paper[] with hfUpvotes populated.\n async fetchForDate(date) {\n var _a2, _b, _c, _d, _e;\n const url = `https://huggingface.co/api/daily_papers?date=${date}`;\n const response = await (0, import_obsidian4.requestUrl)({ url, method: \"GET\" });\n const entries = JSON.parse(response.text);\n if (!Array.isArray(entries))\n return [];\n const papers = [];\n for (const entry of entries) {\n const p = entry.paper;\n if (!(p == null ? void 0 : p.id))\n continue;\n const baseId = p.id.trim();\n const authors = ((_a2 = p.authors) != null ? _a2 : []).map((a) => a.name).filter(Boolean);\n const published = (_b = p.publishedAt) != null ? _b : \"\";\n const htmlLink = `https://arxiv.org/abs/${baseId}`;\n const pdfLink = `https://arxiv.org/pdf/${baseId}`;\n const hfLink = `https://huggingface.co/papers/${baseId}`;\n papers.push({\n id: `arxiv:${baseId}`,\n // normalised without version so we can match\n title: (_c = p.title) != null ? _c : \"\",\n abstract: (_d = p.summary) != null ? _d : \"\",\n authors,\n categories: [],\n published,\n updated: published,\n links: { html: htmlLink, pdf: pdfLink, hf: hfLink },\n source: \"hf\",\n hfUpvotes: (_e = p.upvotes) != null ? _e : 0\n });\n }\n papers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.hfUpvotes) != null ? _a3 : 0) - ((_b2 = a.hfUpvotes) != null ? _b2 : 0);\n });\n return papers;\n }\n // PaperSource interface: not used in normal pipeline (we call fetchForDate directly)\n async fetch(_params) {\n return [];\n }\n};\n\n// src/scoring/interest.ts\nfunction normalize(text) {\n return text.toLowerCase().replace(/\\s+/g, \" \").trim();\n}\nfunction computeInterestHits(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).map((kw) => kw.keyword);\n}\nfunction computeWeightedInterestScore(paper, keywords) {\n const haystack = normalize(`${paper.title} ${paper.abstract}`);\n return keywords.filter((kw) => haystack.includes(normalize(kw.keyword))).reduce((sum, kw) => sum + kw.weight, 0);\n}\n\n// src/scoring/rank.ts\nfunction rankPapers(papers, interestKeywords) {\n const scored = papers.map((paper) => {\n var _a2;\n const interestHits = computeInterestHits(paper, interestKeywords);\n const interestScore = computeWeightedInterestScore(paper, interestKeywords);\n const hfScore = Math.log1p((_a2 = paper.hfUpvotes) != null ? _a2 : 0) * 10;\n const rankScore = hfScore + interestScore;\n return {\n ...paper,\n interestHits,\n _rankScore: rankScore\n };\n });\n scored.sort((a, b) => {\n if (Math.abs(b._rankScore - a._rankScore) > 1e-3)\n return b._rankScore - a._rankScore;\n const dateA = new Date(a.updated || a.published).getTime();\n const dateB = new Date(b.updated || b.published).getTime();\n return dateB - dateA;\n });\n return scored.map(({ _rankScore: _r, ...paper }) => paper);\n}\n\n// src/storage/paperDownloader.ts\nvar import_obsidian5 = require(\"obsidian\");\nfunction sleep(ms) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\nfunction getArxivId(paperId) {\n return paperId.replace(/^arxiv:/i, \"\");\n}\nfunction safeFilename(id) {\n return id.replace(/[/\\\\:*?\"<>|]/g, \"_\");\n}\nasync function ensureFolder(app, folderPath) {\n if (!folderPath)\n return;\n const normalized = (0, import_obsidian5.normalizePath)(folderPath);\n if (app.vault.getAbstractFileByPath(normalized))\n return;\n const parent = normalized.split(\"/\").slice(0, -1).join(\"/\");\n if (parent)\n await ensureFolder(app, parent);\n try {\n await app.vault.createFolder(normalized);\n } catch (e) {\n }\n}\nasync function downloadOne(app, paper, rootFolder, date, log) {\n const arxivId = getArxivId(paper.id);\n const filename = safeFilename(arxivId);\n if (!paper.links.pdf)\n return;\n const pdfFolder = `${rootFolder}/papers/pdf/${date}`;\n const pdfPath = (0, import_obsidian5.normalizePath)(`${pdfFolder}/${filename}.pdf`);\n if (app.vault.getAbstractFileByPath(pdfPath)) {\n paper.links.localPdf = pdfPath;\n log(`PDF skip (exists): ${filename}`);\n } else {\n try {\n const resp = await (0, import_obsidian5.requestUrl)({ url: paper.links.pdf, method: \"GET\" });\n if (resp.status === 200) {\n await ensureFolder(app, pdfFolder);\n await app.vault.adapter.writeBinary(pdfPath, resp.arrayBuffer);\n paper.links.localPdf = pdfPath;\n log(`PDF saved: ${filename}.pdf (${Math.round(resp.arrayBuffer.byteLength / 1024)} KB)`);\n } else {\n log(`PDF skip (HTTP ${resp.status}): ${filename}`);\n }\n } catch (err) {\n log(`PDF error: ${filename}: ${String(err)}`);\n }\n await sleep(1200);\n }\n}\nasync function downloadPapersForDay(app, papers, settings, log, date) {\n var _a2;\n if (!((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf))\n return;\n log(`Step DOWNLOAD: ${papers.length} papers \\u2192 papers/pdf/${date}/`);\n for (const paper of papers) {\n await downloadOne(app, paper, settings.rootFolder, date, log);\n }\n log(`Step DOWNLOAD: done`);\n}\n\n// src/llm/openaiCompatible.ts\nvar import_obsidian6 = require(\"obsidian\");\nvar OpenAICompatibleProvider = class {\n constructor(baseUrl, apiKey, model) {\n this.baseUrl = baseUrl;\n this.apiKey = apiKey;\n this.model = model;\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f, _g, _h;\n const messages = [];\n if (input.system) {\n messages.push({ role: \"system\", content: input.system });\n }\n messages.push({ role: \"user\", content: input.prompt });\n const body = {\n model: this.model,\n messages,\n temperature: (_a2 = input.temperature) != null ? _a2 : 0.3,\n max_tokens: (_b = input.maxTokens) != null ? _b : 4096\n };\n const url = this.baseUrl.replace(/\\/$/, \"\") + \"/chat/completions\";\n const response = await (0, import_obsidian6.requestUrl)({\n url,\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Authorization\": `Bearer ${this.apiKey}`\n },\n body: JSON.stringify(body)\n });\n const json = response.json;\n const text = (_f = (_e = (_d = (_c = json == null ? void 0 : json.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) != null ? _f : \"\";\n const usage = (json == null ? void 0 : json.usage) ? {\n inputTokens: (_g = json.usage.prompt_tokens) != null ? _g : 0,\n outputTokens: (_h = json.usage.completion_tokens) != null ? _h : 0\n } : void 0;\n return { text, usage, raw: json };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/version.mjs\nvar VERSION = \"0.36.3\";\n\n// node_modules/@anthropic-ai/sdk/_shims/registry.mjs\nvar auto = false;\nvar kind = void 0;\nvar fetch2 = void 0;\nvar Request2 = void 0;\nvar Response2 = void 0;\nvar Headers2 = void 0;\nvar FormData2 = void 0;\nvar Blob2 = void 0;\nvar File2 = void 0;\nvar ReadableStream2 = void 0;\nvar getMultipartRequestOptions = void 0;\nvar getDefaultAgent = void 0;\nvar fileFromPath = void 0;\nvar isFsReadStream = void 0;\nfunction setShims(shims, options = { auto: false }) {\n if (auto) {\n throw new Error(`you must \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` before importing anything else from @anthropic-ai/sdk`);\n }\n if (kind) {\n throw new Error(`can't \\`import '@anthropic-ai/sdk/shims/${shims.kind}'\\` after \\`import '@anthropic-ai/sdk/shims/${kind}'\\``);\n }\n auto = options.auto;\n kind = shims.kind;\n fetch2 = shims.fetch;\n Request2 = shims.Request;\n Response2 = shims.Response;\n Headers2 = shims.Headers;\n FormData2 = shims.FormData;\n Blob2 = shims.Blob;\n File2 = shims.File;\n ReadableStream2 = shims.ReadableStream;\n getMultipartRequestOptions = shims.getMultipartRequestOptions;\n getDefaultAgent = shims.getDefaultAgent;\n fileFromPath = shims.fileFromPath;\n isFsReadStream = shims.isFsReadStream;\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/MultipartBody.mjs\nvar MultipartBody = class {\n constructor(body) {\n this.body = body;\n }\n get [Symbol.toStringTag]() {\n return \"MultipartBody\";\n }\n};\n\n// node_modules/@anthropic-ai/sdk/_shims/web-runtime.mjs\nfunction getRuntime({ manuallyImported } = {}) {\n const recommendation = manuallyImported ? `You may need to use polyfills` : `Add one of these imports before your first \\`import \\u2026 from '@anthropic-ai/sdk'\\`:\n- \\`import '@anthropic-ai/sdk/shims/node'\\` (if you're running on Node)\n- \\`import '@anthropic-ai/sdk/shims/web'\\` (otherwise)\n`;\n let _fetch, _Request, _Response, _Headers;\n try {\n _fetch = fetch;\n _Request = Request;\n _Response = Response;\n _Headers = Headers;\n } catch (error) {\n throw new Error(`this environment is missing the following Web Fetch API type: ${error.message}. ${recommendation}`);\n }\n return {\n kind: \"web\",\n fetch: _fetch,\n Request: _Request,\n Response: _Response,\n Headers: _Headers,\n FormData: (\n // @ts-ignore\n typeof FormData !== \"undefined\" ? FormData : class FormData {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`);\n }\n }\n ),\n Blob: typeof Blob !== \"undefined\" ? Blob : class Blob {\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`);\n }\n },\n File: (\n // @ts-ignore\n typeof File !== \"undefined\" ? File : class File {\n // @ts-ignore\n constructor() {\n throw new Error(`file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`);\n }\n }\n ),\n ReadableStream: (\n // @ts-ignore\n typeof ReadableStream !== \"undefined\" ? ReadableStream : class ReadableStream {\n // @ts-ignore\n constructor() {\n throw new Error(`streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`);\n }\n }\n ),\n getMultipartRequestOptions: async (form, opts) => ({\n ...opts,\n body: new MultipartBody(form)\n }),\n getDefaultAgent: (url) => void 0,\n fileFromPath: () => {\n throw new Error(\"The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/anthropics/anthropic-sdk-typescript#file-uploads\");\n },\n isFsReadStream: (value) => false\n };\n}\n\n// node_modules/@anthropic-ai/sdk/_shims/index.mjs\nif (!kind)\n setShims(getRuntime(), { auto: true });\n\n// node_modules/@anthropic-ai/sdk/error.mjs\nvar AnthropicError = class extends Error {\n};\nvar APIError = class extends AnthropicError {\n constructor(status, error, message, headers) {\n super(`${APIError.makeMessage(status, error, message)}`);\n this.status = status;\n this.headers = headers;\n this.request_id = headers == null ? void 0 : headers[\"request-id\"];\n this.error = error;\n }\n static makeMessage(status, error, message) {\n const msg = (error == null ? void 0 : error.message) ? typeof error.message === \"string\" ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message;\n if (status && msg) {\n return `${status} ${msg}`;\n }\n if (status) {\n return `${status} status code (no body)`;\n }\n if (msg) {\n return msg;\n }\n return \"(no status code or body)\";\n }\n static generate(status, errorResponse, message, headers) {\n if (!status || !headers) {\n return new APIConnectionError({ message, cause: castToError(errorResponse) });\n }\n const error = errorResponse;\n if (status === 400) {\n return new BadRequestError(status, error, message, headers);\n }\n if (status === 401) {\n return new AuthenticationError(status, error, message, headers);\n }\n if (status === 403) {\n return new PermissionDeniedError(status, error, message, headers);\n }\n if (status === 404) {\n return new NotFoundError(status, error, message, headers);\n }\n if (status === 409) {\n return new ConflictError(status, error, message, headers);\n }\n if (status === 422) {\n return new UnprocessableEntityError(status, error, message, headers);\n }\n if (status === 429) {\n return new RateLimitError(status, error, message, headers);\n }\n if (status >= 500) {\n return new InternalServerError(status, error, message, headers);\n }\n return new APIError(status, error, message, headers);\n }\n};\nvar APIUserAbortError = class extends APIError {\n constructor({ message } = {}) {\n super(void 0, void 0, message || \"Request was aborted.\", void 0);\n }\n};\nvar APIConnectionError = class extends APIError {\n constructor({ message, cause }) {\n super(void 0, void 0, message || \"Connection error.\", void 0);\n if (cause)\n this.cause = cause;\n }\n};\nvar APIConnectionTimeoutError = class extends APIConnectionError {\n constructor({ message } = {}) {\n super({ message: message != null ? message : \"Request timed out.\" });\n }\n};\nvar BadRequestError = class extends APIError {\n};\nvar AuthenticationError = class extends APIError {\n};\nvar PermissionDeniedError = class extends APIError {\n};\nvar NotFoundError = class extends APIError {\n};\nvar ConflictError = class extends APIError {\n};\nvar UnprocessableEntityError = class extends APIError {\n};\nvar RateLimitError = class extends APIError {\n};\nvar InternalServerError = class extends APIError {\n};\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/line.mjs\nvar LineDecoder = class {\n constructor() {\n this.buffer = [];\n this.trailingCR = false;\n }\n decode(chunk) {\n let text = this.decodeText(chunk);\n if (this.trailingCR) {\n text = \"\\r\" + text;\n this.trailingCR = false;\n }\n if (text.endsWith(\"\\r\")) {\n this.trailingCR = true;\n text = text.slice(0, -1);\n }\n if (!text) {\n return [];\n }\n const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || \"\");\n let lines = text.split(LineDecoder.NEWLINE_REGEXP);\n if (trailingNewline) {\n lines.pop();\n }\n if (lines.length === 1 && !trailingNewline) {\n this.buffer.push(lines[0]);\n return [];\n }\n if (this.buffer.length > 0) {\n lines = [this.buffer.join(\"\") + lines[0], ...lines.slice(1)];\n this.buffer = [];\n }\n if (!trailingNewline) {\n this.buffer = [lines.pop() || \"\"];\n }\n return lines;\n }\n decodeText(bytes) {\n var _a2;\n if (bytes == null)\n return \"\";\n if (typeof bytes === \"string\")\n return bytes;\n if (typeof Buffer !== \"undefined\") {\n if (bytes instanceof Buffer) {\n return bytes.toString();\n }\n if (bytes instanceof Uint8Array) {\n return Buffer.from(bytes).toString();\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global \"Buffer\" defined, which this library assumes to be Node. Please report this error.`);\n }\n if (typeof TextDecoder !== \"undefined\") {\n if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {\n (_a2 = this.textDecoder) != null ? _a2 : this.textDecoder = new TextDecoder(\"utf8\");\n return this.textDecoder.decode(bytes);\n }\n throw new AnthropicError(`Unexpected: received non-Uint8Array/ArrayBuffer (${bytes.constructor.name}) in a web platform. Please report this error.`);\n }\n throw new AnthropicError(`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`);\n }\n flush() {\n if (!this.buffer.length && !this.trailingCR) {\n return [];\n }\n const lines = [this.buffer.join(\"\")];\n this.buffer = [];\n this.trailingCR = false;\n return lines;\n }\n};\nLineDecoder.NEWLINE_CHARS = /* @__PURE__ */ new Set([\"\\n\", \"\\r\"]);\nLineDecoder.NEWLINE_REGEXP = /\\r\\n|[\\n\\r]/g;\n\n// node_modules/@anthropic-ai/sdk/internal/stream-utils.mjs\nfunction ReadableStreamToAsyncIterable(stream) {\n if (stream[Symbol.asyncIterator])\n return stream;\n const reader = stream.getReader();\n return {\n async next() {\n try {\n const result = await reader.read();\n if (result == null ? void 0 : result.done)\n reader.releaseLock();\n return result;\n } catch (e) {\n reader.releaseLock();\n throw e;\n }\n },\n async return() {\n const cancelPromise = reader.cancel();\n reader.releaseLock();\n await cancelPromise;\n return { done: true, value: void 0 };\n },\n [Symbol.asyncIterator]() {\n return this;\n }\n };\n}\n\n// node_modules/@anthropic-ai/sdk/streaming.mjs\nvar Stream = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n static fromSSEResponse(response, controller) {\n let consumed = false;\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const sse of _iterSSEMessages(response, controller)) {\n if (sse.event === \"completion\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"message_start\" || sse.event === \"message_delta\" || sse.event === \"message_stop\" || sse.event === \"content_block_start\" || sse.event === \"content_block_delta\" || sse.event === \"content_block_stop\") {\n try {\n yield JSON.parse(sse.data);\n } catch (e) {\n console.error(`Could not parse message into JSON:`, sse.data);\n console.error(`From chunk:`, sse.raw);\n throw e;\n }\n }\n if (sse.event === \"ping\") {\n continue;\n }\n if (sse.event === \"error\") {\n throw APIError.generate(void 0, `SSE Error: ${sse.data}`, sse.data, createResponseHeaders(response.headers));\n }\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n /**\n * Generates a Stream from a newline-separated ReadableStream\n * where each item is a JSON value.\n */\n static fromReadableStream(readableStream, controller) {\n let consumed = false;\n async function* iterLines() {\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(readableStream);\n for await (const chunk of iter) {\n for (const line of lineDecoder.decode(chunk)) {\n yield line;\n }\n }\n for (const line of lineDecoder.flush()) {\n yield line;\n }\n }\n async function* iterator() {\n if (consumed) {\n throw new Error(\"Cannot iterate over a consumed stream, use `.tee()` to split the stream.\");\n }\n consumed = true;\n let done = false;\n try {\n for await (const line of iterLines()) {\n if (done)\n continue;\n if (line)\n yield JSON.parse(line);\n }\n done = true;\n } catch (e) {\n if (e instanceof Error && e.name === \"AbortError\")\n return;\n throw e;\n } finally {\n if (!done)\n controller.abort();\n }\n }\n return new Stream(iterator, controller);\n }\n [Symbol.asyncIterator]() {\n return this.iterator();\n }\n /**\n * Splits the stream into two streams which can be\n * independently read from at different speeds.\n */\n tee() {\n const left = [];\n const right = [];\n const iterator = this.iterator();\n const teeIterator = (queue) => {\n return {\n next: () => {\n if (queue.length === 0) {\n const result = iterator.next();\n left.push(result);\n right.push(result);\n }\n return queue.shift();\n }\n };\n };\n return [\n new Stream(() => teeIterator(left), this.controller),\n new Stream(() => teeIterator(right), this.controller)\n ];\n }\n /**\n * Converts this stream to a newline-separated ReadableStream of\n * JSON stringified values in the stream\n * which can be turned back into a Stream with `Stream.fromReadableStream()`.\n */\n toReadableStream() {\n const self = this;\n let iter;\n const encoder = new TextEncoder();\n return new ReadableStream2({\n async start() {\n iter = self[Symbol.asyncIterator]();\n },\n async pull(ctrl) {\n try {\n const { value, done } = await iter.next();\n if (done)\n return ctrl.close();\n const bytes = encoder.encode(JSON.stringify(value) + \"\\n\");\n ctrl.enqueue(bytes);\n } catch (err) {\n ctrl.error(err);\n }\n },\n async cancel() {\n var _a2;\n await ((_a2 = iter.return) == null ? void 0 : _a2.call(iter));\n }\n });\n }\n};\nasync function* _iterSSEMessages(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n const sseDecoder = new SSEDecoder();\n const lineDecoder = new LineDecoder();\n const iter = ReadableStreamToAsyncIterable(response.body);\n for await (const sseChunk of iterSSEChunks(iter)) {\n for (const line of lineDecoder.decode(sseChunk)) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n }\n for (const line of lineDecoder.flush()) {\n const sse = sseDecoder.decode(line);\n if (sse)\n yield sse;\n }\n}\nasync function* iterSSEChunks(iterator) {\n let data = new Uint8Array();\n for await (const chunk of iterator) {\n if (chunk == null) {\n continue;\n }\n const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) : typeof chunk === \"string\" ? new TextEncoder().encode(chunk) : chunk;\n let newData = new Uint8Array(data.length + binaryChunk.length);\n newData.set(data);\n newData.set(binaryChunk, data.length);\n data = newData;\n let patternIndex;\n while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) {\n yield data.slice(0, patternIndex);\n data = data.slice(patternIndex);\n }\n }\n if (data.length > 0) {\n yield data;\n }\n}\nfunction findDoubleNewlineIndex(buffer) {\n const newline = 10;\n const carriage = 13;\n for (let i = 0; i < buffer.length - 2; i++) {\n if (buffer[i] === newline && buffer[i + 1] === newline) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === carriage) {\n return i + 2;\n }\n if (buffer[i] === carriage && buffer[i + 1] === newline && i + 3 < buffer.length && buffer[i + 2] === carriage && buffer[i + 3] === newline) {\n return i + 4;\n }\n }\n return -1;\n}\nvar SSEDecoder = class {\n constructor() {\n this.event = null;\n this.data = [];\n this.chunks = [];\n }\n decode(line) {\n if (line.endsWith(\"\\r\")) {\n line = line.substring(0, line.length - 1);\n }\n if (!line) {\n if (!this.event && !this.data.length)\n return null;\n const sse = {\n event: this.event,\n data: this.data.join(\"\\n\"),\n raw: this.chunks\n };\n this.event = null;\n this.data = [];\n this.chunks = [];\n return sse;\n }\n this.chunks.push(line);\n if (line.startsWith(\":\")) {\n return null;\n }\n let [fieldname, _, value] = partition(line, \":\");\n if (value.startsWith(\" \")) {\n value = value.substring(1);\n }\n if (fieldname === \"event\") {\n this.event = value;\n } else if (fieldname === \"data\") {\n this.data.push(value);\n }\n return null;\n }\n};\nfunction partition(str, delimiter) {\n const index = str.indexOf(delimiter);\n if (index !== -1) {\n return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)];\n }\n return [str, \"\", \"\"];\n}\n\n// node_modules/@anthropic-ai/sdk/uploads.mjs\nvar isResponseLike = (value) => value != null && typeof value === \"object\" && typeof value.url === \"string\" && typeof value.blob === \"function\";\nvar isFileLike = (value) => value != null && typeof value === \"object\" && typeof value.name === \"string\" && typeof value.lastModified === \"number\" && isBlobLike(value);\nvar isBlobLike = (value) => value != null && typeof value === \"object\" && typeof value.size === \"number\" && typeof value.type === \"string\" && typeof value.text === \"function\" && typeof value.slice === \"function\" && typeof value.arrayBuffer === \"function\";\nasync function toFile(value, name, options) {\n var _a2, _b, _c;\n value = await value;\n if (isFileLike(value)) {\n return value;\n }\n if (isResponseLike(value)) {\n const blob = await value.blob();\n name || (name = (_a2 = new URL(value.url).pathname.split(/[\\\\/]/).pop()) != null ? _a2 : \"unknown_file\");\n const data = isBlobLike(blob) ? [await blob.arrayBuffer()] : [blob];\n return new File2(data, name, options);\n }\n const bits = await getBytes(value);\n name || (name = (_b = getName(value)) != null ? _b : \"unknown_file\");\n if (!(options == null ? void 0 : options.type)) {\n const type = (_c = bits[0]) == null ? void 0 : _c.type;\n if (typeof type === \"string\") {\n options = { ...options, type };\n }\n }\n return new File2(bits, name, options);\n}\nasync function getBytes(value) {\n var _a2;\n let parts = [];\n if (typeof value === \"string\" || ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.\n value instanceof ArrayBuffer) {\n parts.push(value);\n } else if (isBlobLike(value)) {\n parts.push(await value.arrayBuffer());\n } else if (isAsyncIterableIterator(value)) {\n for await (const chunk of value) {\n parts.push(chunk);\n }\n } else {\n throw new Error(`Unexpected data type: ${typeof value}; constructor: ${(_a2 = value == null ? void 0 : value.constructor) == null ? void 0 : _a2.name}; props: ${propsForError(value)}`);\n }\n return parts;\n}\nfunction propsForError(value) {\n const props = Object.getOwnPropertyNames(value);\n return `[${props.map((p) => `\"${p}\"`).join(\", \")}]`;\n}\nfunction getName(value) {\n var _a2;\n return getStringFromMaybeBuffer(value.name) || getStringFromMaybeBuffer(value.filename) || // For fs.ReadStream\n ((_a2 = getStringFromMaybeBuffer(value.path)) == null ? void 0 : _a2.split(/[\\\\/]/).pop());\n}\nvar getStringFromMaybeBuffer = (x) => {\n if (typeof x === \"string\")\n return x;\n if (typeof Buffer !== \"undefined\" && x instanceof Buffer)\n return String(x);\n return void 0;\n};\nvar isAsyncIterableIterator = (value) => value != null && typeof value === \"object\" && typeof value[Symbol.asyncIterator] === \"function\";\nvar isMultipartBody = (body) => body && typeof body === \"object\" && body.body && body[Symbol.toStringTag] === \"MultipartBody\";\n\n// node_modules/@anthropic-ai/sdk/core.mjs\nvar __classPrivateFieldSet = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _AbstractPage_client;\nasync function defaultParseResponse(props) {\n const { response } = props;\n if (props.options.stream) {\n debug(\"response\", response.status, response.url, response.headers, response.body);\n if (props.options.__streamClass) {\n return props.options.__streamClass.fromSSEResponse(response, props.controller);\n }\n return Stream.fromSSEResponse(response, props.controller);\n }\n if (response.status === 204) {\n return null;\n }\n if (props.options.__binaryResponse) {\n return response;\n }\n const contentType = response.headers.get(\"content-type\");\n const isJSON = (contentType == null ? void 0 : contentType.includes(\"application/json\")) || (contentType == null ? void 0 : contentType.includes(\"application/vnd.api+json\"));\n if (isJSON) {\n const json = await response.json();\n debug(\"response\", response.status, response.url, response.headers, json);\n return _addRequestID(json, response);\n }\n const text = await response.text();\n debug(\"response\", response.status, response.url, response.headers, text);\n return text;\n}\nfunction _addRequestID(value, response) {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return value;\n }\n return Object.defineProperty(value, \"_request_id\", {\n value: response.headers.get(\"request-id\"),\n enumerable: false\n });\n}\nvar APIPromise = class extends Promise {\n constructor(responsePromise, parseResponse = defaultParseResponse) {\n super((resolve) => {\n resolve(null);\n });\n this.responsePromise = responsePromise;\n this.parseResponse = parseResponse;\n }\n _thenUnwrap(transform) {\n return new APIPromise(this.responsePromise, async (props) => _addRequestID(transform(await this.parseResponse(props), props), props.response));\n }\n /**\n * Gets the raw `Response` instance instead of parsing the response\n * data.\n *\n * If you want to parse the response body but still get the `Response`\n * instance, you can use {@link withResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n asResponse() {\n return this.responsePromise.then((p) => p.response);\n }\n /**\n * Gets the parsed response data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * If you just want to get the raw `Response` instance without parsing it,\n * you can use {@link asResponse()}.\n *\n * 👋 Getting the wrong TypeScript type for `Response`?\n * Try setting `\"moduleResolution\": \"NodeNext\"` if you can,\n * or add one of these imports before your first `import … from '@anthropic-ai/sdk'`:\n * - `import '@anthropic-ai/sdk/shims/node'` (if you're running on Node)\n * - `import '@anthropic-ai/sdk/shims/web'` (otherwise)\n */\n async withResponse() {\n const [data, response] = await Promise.all([this.parse(), this.asResponse()]);\n return { data, response, request_id: response.headers.get(\"request-id\") };\n }\n parse() {\n if (!this.parsedPromise) {\n this.parsedPromise = this.responsePromise.then(this.parseResponse);\n }\n return this.parsedPromise;\n }\n then(onfulfilled, onrejected) {\n return this.parse().then(onfulfilled, onrejected);\n }\n catch(onrejected) {\n return this.parse().catch(onrejected);\n }\n finally(onfinally) {\n return this.parse().finally(onfinally);\n }\n};\nvar APIClient = class {\n constructor({\n baseURL,\n maxRetries = 2,\n timeout = 6e5,\n // 10 minutes\n httpAgent,\n fetch: overriddenFetch\n }) {\n this.baseURL = baseURL;\n this.maxRetries = validatePositiveInteger(\"maxRetries\", maxRetries);\n this.timeout = validatePositiveInteger(\"timeout\", timeout);\n this.httpAgent = httpAgent;\n this.fetch = overriddenFetch != null ? overriddenFetch : fetch2;\n }\n authHeaders(opts) {\n return {};\n }\n /**\n * Override this to add your own default headers, for example:\n *\n * {\n * ...super.defaultHeaders(),\n * Authorization: 'Bearer 123',\n * }\n */\n defaultHeaders(opts) {\n return {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.getUserAgent(),\n ...getPlatformHeaders(),\n ...this.authHeaders(opts)\n };\n }\n /**\n * Override this to add your own headers validation:\n */\n validateHeaders(headers, customHeaders) {\n }\n defaultIdempotencyKey() {\n return `stainless-node-retry-${uuid4()}`;\n }\n get(path, opts) {\n return this.methodRequest(\"get\", path, opts);\n }\n post(path, opts) {\n return this.methodRequest(\"post\", path, opts);\n }\n patch(path, opts) {\n return this.methodRequest(\"patch\", path, opts);\n }\n put(path, opts) {\n return this.methodRequest(\"put\", path, opts);\n }\n delete(path, opts) {\n return this.methodRequest(\"delete\", path, opts);\n }\n methodRequest(method, path, opts) {\n return this.request(Promise.resolve(opts).then(async (opts2) => {\n const body = opts2 && isBlobLike(opts2 == null ? void 0 : opts2.body) ? new DataView(await opts2.body.arrayBuffer()) : (opts2 == null ? void 0 : opts2.body) instanceof DataView ? opts2.body : (opts2 == null ? void 0 : opts2.body) instanceof ArrayBuffer ? new DataView(opts2.body) : opts2 && ArrayBuffer.isView(opts2 == null ? void 0 : opts2.body) ? new DataView(opts2.body.buffer) : opts2 == null ? void 0 : opts2.body;\n return { method, path, ...opts2, body };\n }));\n }\n getAPIList(path, Page2, opts) {\n return this.requestAPIList(Page2, { method: \"get\", path, ...opts });\n }\n calculateContentLength(body) {\n if (typeof body === \"string\") {\n if (typeof Buffer !== \"undefined\") {\n return Buffer.byteLength(body, \"utf8\").toString();\n }\n if (typeof TextEncoder !== \"undefined\") {\n const encoder = new TextEncoder();\n const encoded = encoder.encode(body);\n return encoded.length.toString();\n }\n } else if (ArrayBuffer.isView(body)) {\n return body.byteLength.toString();\n }\n return null;\n }\n buildRequest(options, { retryCount = 0 } = {}) {\n var _a2, _b, _c, _d, _e, _f;\n const { method, path, query, headers = {} } = options;\n const body = ArrayBuffer.isView(options.body) || options.__binaryRequest && typeof options.body === \"string\" ? options.body : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null;\n const contentLength = this.calculateContentLength(body);\n const url = this.buildURL(path, query);\n if (\"timeout\" in options)\n validatePositiveInteger(\"timeout\", options.timeout);\n const timeout = (_a2 = options.timeout) != null ? _a2 : this.timeout;\n const httpAgent = (_c = (_b = options.httpAgent) != null ? _b : this.httpAgent) != null ? _c : getDefaultAgent(url);\n const minAgentTimeout = timeout + 1e3;\n if (typeof ((_d = httpAgent == null ? void 0 : httpAgent.options) == null ? void 0 : _d.timeout) === \"number\" && minAgentTimeout > ((_e = httpAgent.options.timeout) != null ? _e : 0)) {\n httpAgent.options.timeout = minAgentTimeout;\n }\n if (this.idempotencyHeader && method !== \"get\") {\n if (!options.idempotencyKey)\n options.idempotencyKey = this.defaultIdempotencyKey();\n headers[this.idempotencyHeader] = options.idempotencyKey;\n }\n const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount });\n const req = {\n method,\n ...body && { body },\n headers: reqHeaders,\n ...httpAgent && { agent: httpAgent },\n // @ts-ignore node-fetch uses a custom AbortSignal type that is\n // not compatible with standard web types\n signal: (_f = options.signal) != null ? _f : null\n };\n return { req, url, timeout };\n }\n buildHeaders({ options, headers, contentLength, retryCount }) {\n const reqHeaders = {};\n if (contentLength) {\n reqHeaders[\"content-length\"] = contentLength;\n }\n const defaultHeaders = this.defaultHeaders(options);\n applyHeadersMut(reqHeaders, defaultHeaders);\n applyHeadersMut(reqHeaders, headers);\n if (isMultipartBody(options.body) && kind !== \"node\") {\n delete reqHeaders[\"content-type\"];\n }\n if (getHeader(defaultHeaders, \"x-stainless-retry-count\") === void 0 && getHeader(headers, \"x-stainless-retry-count\") === void 0) {\n reqHeaders[\"x-stainless-retry-count\"] = String(retryCount);\n }\n this.validateHeaders(reqHeaders, headers);\n return reqHeaders;\n }\n /**\n * Used as a callback for mutating the given `FinalRequestOptions` object.\n */\n async prepareOptions(options) {\n }\n /**\n * Used as a callback for mutating the given `RequestInit` object.\n *\n * This is useful for cases where you want to add certain headers based off of\n * the request properties, e.g. `method` or `url`.\n */\n async prepareRequest(request, { url, options }) {\n }\n parseHeaders(headers) {\n return !headers ? {} : Symbol.iterator in headers ? Object.fromEntries(Array.from(headers).map((header) => [...header])) : { ...headers };\n }\n makeStatusError(status, error, message, headers) {\n return APIError.generate(status, error, message, headers);\n }\n request(options, remainingRetries = null) {\n return new APIPromise(this.makeRequest(options, remainingRetries));\n }\n async makeRequest(optionsInput, retriesRemaining) {\n var _a2, _b, _c;\n const options = await optionsInput;\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n if (retriesRemaining == null) {\n retriesRemaining = maxRetries;\n }\n await this.prepareOptions(options);\n const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining });\n await this.prepareRequest(req, { url, options });\n debug(\"request\", url, options, req.headers);\n if ((_b = options.signal) == null ? void 0 : _b.aborted) {\n throw new APIUserAbortError();\n }\n const controller = new AbortController();\n const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError);\n if (response instanceof Error) {\n if ((_c = options.signal) == null ? void 0 : _c.aborted) {\n throw new APIUserAbortError();\n }\n if (retriesRemaining) {\n return this.retryRequest(options, retriesRemaining);\n }\n if (response.name === \"AbortError\") {\n throw new APIConnectionTimeoutError();\n }\n throw new APIConnectionError({ cause: response });\n }\n const responseHeaders = createResponseHeaders(response.headers);\n if (!response.ok) {\n if (retriesRemaining && this.shouldRetry(response)) {\n const retryMessage2 = `retrying, ${retriesRemaining} attempts remaining`;\n debug(`response (error; ${retryMessage2})`, response.status, url, responseHeaders);\n return this.retryRequest(options, retriesRemaining, responseHeaders);\n }\n const errText = await response.text().catch((e) => castToError(e).message);\n const errJSON = safeJSON(errText);\n const errMessage = errJSON ? void 0 : errText;\n const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;\n debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);\n const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);\n throw err;\n }\n return { response, options, controller };\n }\n requestAPIList(Page2, options) {\n const request = this.makeRequest(options, null);\n return new PagePromise(this, request, Page2);\n }\n buildURL(path, query) {\n const url = isAbsoluteURL(path) ? new URL(path) : new URL(this.baseURL + (this.baseURL.endsWith(\"/\") && path.startsWith(\"/\") ? path.slice(1) : path));\n const defaultQuery = this.defaultQuery();\n if (!isEmptyObj(defaultQuery)) {\n query = { ...defaultQuery, ...query };\n }\n if (typeof query === \"object\" && query && !Array.isArray(query)) {\n url.search = this.stringifyQuery(query);\n }\n return url.toString();\n }\n stringifyQuery(query) {\n return Object.entries(query).filter(([_, value]) => typeof value !== \"undefined\").map(([key, value]) => {\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;\n }\n if (value === null) {\n return `${encodeURIComponent(key)}=`;\n }\n throw new AnthropicError(`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`);\n }).join(\"&\");\n }\n async fetchWithTimeout(url, init, ms, controller) {\n const { signal, ...options } = init || {};\n if (signal)\n signal.addEventListener(\"abort\", () => controller.abort());\n const timeout = setTimeout(() => controller.abort(), ms);\n const fetchOptions = {\n signal: controller.signal,\n ...options\n };\n if (fetchOptions.method) {\n fetchOptions.method = fetchOptions.method.toUpperCase();\n }\n return (\n // use undefined this binding; fetch errors if bound to something else in browser/cloudflare\n this.fetch.call(void 0, url, fetchOptions).finally(() => {\n clearTimeout(timeout);\n })\n );\n }\n shouldRetry(response) {\n const shouldRetryHeader = response.headers.get(\"x-should-retry\");\n if (shouldRetryHeader === \"true\")\n return true;\n if (shouldRetryHeader === \"false\")\n return false;\n if (response.status === 408)\n return true;\n if (response.status === 409)\n return true;\n if (response.status === 429)\n return true;\n if (response.status >= 500)\n return true;\n return false;\n }\n async retryRequest(options, retriesRemaining, responseHeaders) {\n var _a2;\n let timeoutMillis;\n const retryAfterMillisHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after-ms\"];\n if (retryAfterMillisHeader) {\n const timeoutMs = parseFloat(retryAfterMillisHeader);\n if (!Number.isNaN(timeoutMs)) {\n timeoutMillis = timeoutMs;\n }\n }\n const retryAfterHeader = responseHeaders == null ? void 0 : responseHeaders[\"retry-after\"];\n if (retryAfterHeader && !timeoutMillis) {\n const timeoutSeconds = parseFloat(retryAfterHeader);\n if (!Number.isNaN(timeoutSeconds)) {\n timeoutMillis = timeoutSeconds * 1e3;\n } else {\n timeoutMillis = Date.parse(retryAfterHeader) - Date.now();\n }\n }\n if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1e3)) {\n const maxRetries = (_a2 = options.maxRetries) != null ? _a2 : this.maxRetries;\n timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);\n }\n await sleep2(timeoutMillis);\n return this.makeRequest(options, retriesRemaining - 1);\n }\n calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {\n const initialRetryDelay = 0.5;\n const maxRetryDelay = 8;\n const numRetries = maxRetries - retriesRemaining;\n const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay);\n const jitter = 1 - Math.random() * 0.25;\n return sleepSeconds * jitter * 1e3;\n }\n getUserAgent() {\n return `${this.constructor.name}/JS ${VERSION}`;\n }\n};\nvar AbstractPage = class {\n constructor(client, response, body, options) {\n _AbstractPage_client.set(this, void 0);\n __classPrivateFieldSet(this, _AbstractPage_client, client, \"f\");\n this.options = options;\n this.response = response;\n this.body = body;\n }\n hasNextPage() {\n const items = this.getPaginatedItems();\n if (!items.length)\n return false;\n return this.nextPageInfo() != null;\n }\n async getNextPage() {\n const nextInfo = this.nextPageInfo();\n if (!nextInfo) {\n throw new AnthropicError(\"No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.\");\n }\n const nextOptions = { ...this.options };\n if (\"params\" in nextInfo && typeof nextOptions.query === \"object\") {\n nextOptions.query = { ...nextOptions.query, ...nextInfo.params };\n } else if (\"url\" in nextInfo) {\n const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()];\n for (const [key, value] of params) {\n nextInfo.url.searchParams.set(key, value);\n }\n nextOptions.query = void 0;\n nextOptions.path = nextInfo.url.toString();\n }\n return await __classPrivateFieldGet(this, _AbstractPage_client, \"f\").requestAPIList(this.constructor, nextOptions);\n }\n async *iterPages() {\n let page = this;\n yield page;\n while (page.hasNextPage()) {\n page = await page.getNextPage();\n yield page;\n }\n }\n async *[(_AbstractPage_client = /* @__PURE__ */ new WeakMap(), Symbol.asyncIterator)]() {\n for await (const page of this.iterPages()) {\n for (const item of page.getPaginatedItems()) {\n yield item;\n }\n }\n }\n};\nvar PagePromise = class extends APIPromise {\n constructor(client, request, Page2) {\n super(request, async (props) => new Page2(client, props.response, await defaultParseResponse(props), props.options));\n }\n /**\n * Allow auto-paginating iteration on an unawaited list call, eg:\n *\n * for await (const item of client.items.list()) {\n * console.log(item)\n * }\n */\n async *[Symbol.asyncIterator]() {\n const page = await this;\n for await (const item of page) {\n yield item;\n }\n }\n};\nvar createResponseHeaders = (headers) => {\n return new Proxy(Object.fromEntries(\n // @ts-ignore\n headers.entries()\n ), {\n get(target, name) {\n const key = name.toString();\n return target[key.toLowerCase()] || target[key];\n }\n });\n};\nvar requestOptionsKeys = {\n method: true,\n path: true,\n query: true,\n body: true,\n headers: true,\n maxRetries: true,\n stream: true,\n timeout: true,\n httpAgent: true,\n signal: true,\n idempotencyKey: true,\n __binaryRequest: true,\n __binaryResponse: true,\n __streamClass: true\n};\nvar isRequestOptions = (obj) => {\n return typeof obj === \"object\" && obj !== null && !isEmptyObj(obj) && Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k));\n};\nvar getPlatformProperties = () => {\n var _a2, _b;\n if (typeof Deno !== \"undefined\" && Deno.build != null) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(Deno.build.os),\n \"X-Stainless-Arch\": normalizeArch(Deno.build.arch),\n \"X-Stainless-Runtime\": \"deno\",\n \"X-Stainless-Runtime-Version\": typeof Deno.version === \"string\" ? Deno.version : (_b = (_a2 = Deno.version) == null ? void 0 : _a2.deno) != null ? _b : \"unknown\"\n };\n }\n if (typeof EdgeRuntime !== \"undefined\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": `other:${EdgeRuntime}`,\n \"X-Stainless-Runtime\": \"edge\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n if (Object.prototype.toString.call(typeof process !== \"undefined\" ? process : 0) === \"[object process]\") {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": normalizePlatform(process.platform),\n \"X-Stainless-Arch\": normalizeArch(process.arch),\n \"X-Stainless-Runtime\": \"node\",\n \"X-Stainless-Runtime-Version\": process.version\n };\n }\n const browserInfo = getBrowserInfo();\n if (browserInfo) {\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": `browser:${browserInfo.browser}`,\n \"X-Stainless-Runtime-Version\": browserInfo.version\n };\n }\n return {\n \"X-Stainless-Lang\": \"js\",\n \"X-Stainless-Package-Version\": VERSION,\n \"X-Stainless-OS\": \"Unknown\",\n \"X-Stainless-Arch\": \"unknown\",\n \"X-Stainless-Runtime\": \"unknown\",\n \"X-Stainless-Runtime-Version\": \"unknown\"\n };\n};\nfunction getBrowserInfo() {\n if (typeof navigator === \"undefined\" || !navigator) {\n return null;\n }\n const browserPatterns = [\n { key: \"edge\", pattern: /Edge(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /MSIE(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"ie\", pattern: /Trident(?:.*rv\\:(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"chrome\", pattern: /Chrome(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"firefox\", pattern: /Firefox(?:\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?/ },\n { key: \"safari\", pattern: /(?:Version\\W+(\\d+)\\.(\\d+)(?:\\.(\\d+))?)?(?:\\W+Mobile\\S*)?\\W+Safari/ }\n ];\n for (const { key, pattern } of browserPatterns) {\n const match = pattern.exec(navigator.userAgent);\n if (match) {\n const major = match[1] || 0;\n const minor = match[2] || 0;\n const patch = match[3] || 0;\n return { browser: key, version: `${major}.${minor}.${patch}` };\n }\n }\n return null;\n}\nvar normalizeArch = (arch) => {\n if (arch === \"x32\")\n return \"x32\";\n if (arch === \"x86_64\" || arch === \"x64\")\n return \"x64\";\n if (arch === \"arm\")\n return \"arm\";\n if (arch === \"aarch64\" || arch === \"arm64\")\n return \"arm64\";\n if (arch)\n return `other:${arch}`;\n return \"unknown\";\n};\nvar normalizePlatform = (platform) => {\n platform = platform.toLowerCase();\n if (platform.includes(\"ios\"))\n return \"iOS\";\n if (platform === \"android\")\n return \"Android\";\n if (platform === \"darwin\")\n return \"MacOS\";\n if (platform === \"win32\")\n return \"Windows\";\n if (platform === \"freebsd\")\n return \"FreeBSD\";\n if (platform === \"openbsd\")\n return \"OpenBSD\";\n if (platform === \"linux\")\n return \"Linux\";\n if (platform)\n return `Other:${platform}`;\n return \"Unknown\";\n};\nvar _platformHeaders;\nvar getPlatformHeaders = () => {\n return _platformHeaders != null ? _platformHeaders : _platformHeaders = getPlatformProperties();\n};\nvar safeJSON = (text) => {\n try {\n return JSON.parse(text);\n } catch (err) {\n return void 0;\n }\n};\nvar startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;\nvar isAbsoluteURL = (url) => {\n return startsWithSchemeRegexp.test(url);\n};\nvar sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\nvar validatePositiveInteger = (name, n) => {\n if (typeof n !== \"number\" || !Number.isInteger(n)) {\n throw new AnthropicError(`${name} must be an integer`);\n }\n if (n < 0) {\n throw new AnthropicError(`${name} must be a positive integer`);\n }\n return n;\n};\nvar castToError = (err) => {\n if (err instanceof Error)\n return err;\n if (typeof err === \"object\" && err !== null) {\n try {\n return new Error(JSON.stringify(err));\n } catch (e) {\n }\n }\n return new Error(String(err));\n};\nvar readEnv = (env) => {\n var _a2, _b, _c, _d, _e, _f;\n if (typeof process !== \"undefined\") {\n return (_c = (_b = (_a2 = process.env) == null ? void 0 : _a2[env]) == null ? void 0 : _b.trim()) != null ? _c : void 0;\n }\n if (typeof Deno !== \"undefined\") {\n return (_f = (_e = (_d = Deno.env) == null ? void 0 : _d.get) == null ? void 0 : _e.call(_d, env)) == null ? void 0 : _f.trim();\n }\n return void 0;\n};\nfunction isEmptyObj(obj) {\n if (!obj)\n return true;\n for (const _k in obj)\n return false;\n return true;\n}\nfunction hasOwn(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\nfunction applyHeadersMut(targetHeaders, newHeaders) {\n for (const k in newHeaders) {\n if (!hasOwn(newHeaders, k))\n continue;\n const lowerKey = k.toLowerCase();\n if (!lowerKey)\n continue;\n const val = newHeaders[k];\n if (val === null) {\n delete targetHeaders[lowerKey];\n } else if (val !== void 0) {\n targetHeaders[lowerKey] = val;\n }\n }\n}\nfunction debug(action, ...args) {\n var _a2;\n if (typeof process !== \"undefined\" && ((_a2 = process == null ? void 0 : process.env) == null ? void 0 : _a2[\"DEBUG\"]) === \"true\") {\n console.log(`Anthropic:DEBUG:${action}`, ...args);\n }\n}\nvar uuid4 = () => {\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\n const r = Math.random() * 16 | 0;\n const v = c === \"x\" ? r : r & 3 | 8;\n return v.toString(16);\n });\n};\nvar isRunningInBrowser = () => {\n return (\n // @ts-ignore\n typeof window !== \"undefined\" && // @ts-ignore\n typeof window.document !== \"undefined\" && // @ts-ignore\n typeof navigator !== \"undefined\"\n );\n};\nvar isHeadersProtocol = (headers) => {\n return typeof (headers == null ? void 0 : headers.get) === \"function\";\n};\nvar getHeader = (headers, header) => {\n var _a2;\n const lowerCasedHeader = header.toLowerCase();\n if (isHeadersProtocol(headers)) {\n const intercapsHeader = ((_a2 = header[0]) == null ? void 0 : _a2.toUpperCase()) + header.substring(1).replace(/([^\\w])(\\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase());\n for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) {\n const value = headers.get(key);\n if (value) {\n return value;\n }\n }\n }\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === lowerCasedHeader) {\n if (Array.isArray(value)) {\n if (value.length <= 1)\n return value[0];\n console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`);\n return value[0];\n }\n return value;\n }\n }\n return void 0;\n};\n\n// node_modules/@anthropic-ai/sdk/pagination.mjs\nvar Page = class extends AbstractPage {\n constructor(client, response, body, options) {\n super(client, response, body, options);\n this.data = body.data || [];\n this.has_more = body.has_more || false;\n this.first_id = body.first_id || null;\n this.last_id = body.last_id || null;\n }\n getPaginatedItems() {\n var _a2;\n return (_a2 = this.data) != null ? _a2 : [];\n }\n // @deprecated Please use `nextPageInfo()` instead\n nextPageParams() {\n const info = this.nextPageInfo();\n if (!info)\n return null;\n if (\"params\" in info)\n return info.params;\n const params = Object.fromEntries(info.url.searchParams);\n if (!Object.keys(params).length)\n return null;\n return params;\n }\n nextPageInfo() {\n var _a2;\n if ((_a2 = this.options.query) == null ? void 0 : _a2[\"before_id\"]) {\n const firstId = this.first_id;\n if (!firstId) {\n return null;\n }\n return {\n params: {\n before_id: firstId\n }\n };\n }\n const cursor = this.last_id;\n if (!cursor) {\n return null;\n }\n return {\n params: {\n after_id: cursor\n }\n };\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resource.mjs\nvar APIResource = class {\n constructor(client) {\n this._client = client;\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/models.mjs\nvar Models = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}?beta=true`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models?beta=true\", BetaModelInfosPage, { query, ...options });\n }\n};\nvar BetaModelInfosPage = class extends Page {\n};\nModels.BetaModelInfosPage = BetaModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/internal/decoders/jsonl.mjs\nvar JSONLDecoder = class {\n constructor(iterator, controller) {\n this.iterator = iterator;\n this.controller = controller;\n }\n async *decoder() {\n const lineDecoder = new LineDecoder();\n for await (const chunk of this.iterator) {\n for (const line of lineDecoder.decode(chunk)) {\n yield JSON.parse(line);\n }\n }\n for (const line of lineDecoder.flush()) {\n yield JSON.parse(line);\n }\n }\n [Symbol.asyncIterator]() {\n return this.decoder();\n }\n static fromResponse(response, controller) {\n if (!response.body) {\n controller.abort();\n throw new AnthropicError(`Attempted to iterate over a response with no body`);\n }\n return new JSONLDecoder(ReadableStreamToAsyncIterable(response.body), controller);\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/batches.mjs\nvar Batches = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/batches?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n retrieve(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.retrieve(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.get(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n list(params = {}, options) {\n if (isRequestOptions(params)) {\n return this.list({}, params);\n }\n const { betas, ...query } = params;\n return this._client.getAPIList(\"/v1/messages/batches?beta=true\", BetaMessageBatchesPage, {\n query,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n delete(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.delete(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.delete(`/v1/messages/batches/${messageBatchId}?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n cancel(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.cancel(messageBatchId, {}, params);\n }\n const { betas } = params;\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel?beta=true`, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n async results(messageBatchId, params = {}, options) {\n if (isRequestOptions(params)) {\n return this.results(messageBatchId, {}, params);\n }\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n const { betas } = params;\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"message-batches-2024-09-24\"].toString(),\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar BetaMessageBatchesPage = class extends Page {\n};\nBatches.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/_vendor/partial-json-parser/parser.mjs\nvar tokenize = (input) => {\n let current = 0;\n let tokens = [];\n while (current < input.length) {\n let char = input[current];\n if (char === \"\\\\\") {\n current++;\n continue;\n }\n if (char === \"{\") {\n tokens.push({\n type: \"brace\",\n value: \"{\"\n });\n current++;\n continue;\n }\n if (char === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n current++;\n continue;\n }\n if (char === \"[\") {\n tokens.push({\n type: \"paren\",\n value: \"[\"\n });\n current++;\n continue;\n }\n if (char === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n current++;\n continue;\n }\n if (char === \":\") {\n tokens.push({\n type: \"separator\",\n value: \":\"\n });\n current++;\n continue;\n }\n if (char === \",\") {\n tokens.push({\n type: \"delimiter\",\n value: \",\"\n });\n current++;\n continue;\n }\n if (char === '\"') {\n let value = \"\";\n let danglingQuote = false;\n char = input[++current];\n while (char !== '\"') {\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n if (char === \"\\\\\") {\n current++;\n if (current === input.length) {\n danglingQuote = true;\n break;\n }\n value += char + input[current];\n char = input[++current];\n } else {\n value += char;\n char = input[++current];\n }\n }\n char = input[++current];\n if (!danglingQuote) {\n tokens.push({\n type: \"string\",\n value\n });\n }\n continue;\n }\n let WHITESPACE = /\\s/;\n if (char && WHITESPACE.test(char)) {\n current++;\n continue;\n }\n let NUMBERS = /[0-9]/;\n if (char && NUMBERS.test(char) || char === \"-\" || char === \".\") {\n let value = \"\";\n if (char === \"-\") {\n value += char;\n char = input[++current];\n }\n while (char && NUMBERS.test(char) || char === \".\") {\n value += char;\n char = input[++current];\n }\n tokens.push({\n type: \"number\",\n value\n });\n continue;\n }\n let LETTERS = /[a-z]/i;\n if (char && LETTERS.test(char)) {\n let value = \"\";\n while (char && LETTERS.test(char)) {\n if (current === input.length) {\n break;\n }\n value += char;\n char = input[++current];\n }\n if (value == \"true\" || value == \"false\" || value === \"null\") {\n tokens.push({\n type: \"name\",\n value\n });\n } else {\n current++;\n continue;\n }\n continue;\n }\n current++;\n }\n return tokens;\n};\nvar strip = (tokens) => {\n if (tokens.length === 0) {\n return tokens;\n }\n let lastToken = tokens[tokens.length - 1];\n switch (lastToken.type) {\n case \"separator\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n case \"number\":\n let lastCharacterOfLastToken = lastToken.value[lastToken.value.length - 1];\n if (lastCharacterOfLastToken === \".\" || lastCharacterOfLastToken === \"-\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n case \"string\":\n let tokenBeforeTheLastToken = tokens[tokens.length - 2];\n if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"delimiter\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n } else if ((tokenBeforeTheLastToken == null ? void 0 : tokenBeforeTheLastToken.type) === \"brace\" && tokenBeforeTheLastToken.value === \"{\") {\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n }\n break;\n case \"delimiter\":\n tokens = tokens.slice(0, tokens.length - 1);\n return strip(tokens);\n break;\n }\n return tokens;\n};\nvar unstrip = (tokens) => {\n let tail = [];\n tokens.map((token) => {\n if (token.type === \"brace\") {\n if (token.value === \"{\") {\n tail.push(\"}\");\n } else {\n tail.splice(tail.lastIndexOf(\"}\"), 1);\n }\n }\n if (token.type === \"paren\") {\n if (token.value === \"[\") {\n tail.push(\"]\");\n } else {\n tail.splice(tail.lastIndexOf(\"]\"), 1);\n }\n }\n });\n if (tail.length > 0) {\n tail.reverse().map((item) => {\n if (item === \"}\") {\n tokens.push({\n type: \"brace\",\n value: \"}\"\n });\n } else if (item === \"]\") {\n tokens.push({\n type: \"paren\",\n value: \"]\"\n });\n }\n });\n }\n return tokens;\n};\nvar generate = (tokens) => {\n let output = \"\";\n tokens.map((token) => {\n switch (token.type) {\n case \"string\":\n output += '\"' + token.value + '\"';\n break;\n default:\n output += token.value;\n break;\n }\n });\n return output;\n};\nvar partialParse = (input) => JSON.parse(generate(unstrip(strip(tokenize(input)))));\n\n// node_modules/@anthropic-ai/sdk/lib/BetaMessageStream.mjs\nvar __classPrivateFieldSet2 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet2 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _BetaMessageStream_instances;\nvar _BetaMessageStream_currentMessageSnapshot;\nvar _BetaMessageStream_connectedPromise;\nvar _BetaMessageStream_resolveConnectedPromise;\nvar _BetaMessageStream_rejectConnectedPromise;\nvar _BetaMessageStream_endPromise;\nvar _BetaMessageStream_resolveEndPromise;\nvar _BetaMessageStream_rejectEndPromise;\nvar _BetaMessageStream_listeners;\nvar _BetaMessageStream_ended;\nvar _BetaMessageStream_errored;\nvar _BetaMessageStream_aborted;\nvar _BetaMessageStream_catchingPromiseCreated;\nvar _BetaMessageStream_response;\nvar _BetaMessageStream_request_id;\nvar _BetaMessageStream_getFinalMessage;\nvar _BetaMessageStream_getFinalText;\nvar _BetaMessageStream_handleError;\nvar _BetaMessageStream_beginRequest;\nvar _BetaMessageStream_addStreamEvent;\nvar _BetaMessageStream_endRequest;\nvar _BetaMessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY = \"__json_buf\";\nvar BetaMessageStream = class {\n constructor() {\n _BetaMessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _BetaMessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _BetaMessageStream_connectedPromise.set(this, void 0);\n _BetaMessageStream_resolveConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_rejectConnectedPromise.set(this, () => {\n });\n _BetaMessageStream_endPromise.set(this, void 0);\n _BetaMessageStream_resolveEndPromise.set(this, () => {\n });\n _BetaMessageStream_rejectEndPromise.set(this, () => {\n });\n _BetaMessageStream_listeners.set(this, {});\n _BetaMessageStream_ended.set(this, false);\n _BetaMessageStream_errored.set(this, false);\n _BetaMessageStream_aborted.set(this, false);\n _BetaMessageStream_catchingPromiseCreated.set(this, false);\n _BetaMessageStream_response.set(this, void 0);\n _BetaMessageStream_request_id.set(this, void 0);\n _BetaMessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet2(this, _BetaMessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet2(this, _BetaMessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet2(this, _BetaMessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new BetaMessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new BetaMessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet2(this, _BetaMessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_response, response, \"f\");\n __classPrivateFieldSet2(this, _BetaMessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet2(this, _BetaMessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet2(this, _BetaMessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet2(this, _BetaMessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet2(this, _BetaMessageStream_ended, true, \"f\");\n __classPrivateFieldGet2(this, _BetaMessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet2(this, _BetaMessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet2(this, _BetaMessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet2(this, _BetaMessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_endRequest).call(this);\n }\n [(_BetaMessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_listeners = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_ended = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_errored = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_aborted = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_response = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_request_id = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_handleError = /* @__PURE__ */ new WeakMap(), _BetaMessageStream_instances = /* @__PURE__ */ new WeakSet(), _BetaMessageStream_getFinalMessage = function _BetaMessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _BetaMessageStream_getFinalText = function _BetaMessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _BetaMessageStream_beginRequest = function _BetaMessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _BetaMessageStream_addStreamEvent = function _BetaMessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet2(this, _BetaMessageStream_instances, \"m\", _BetaMessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _BetaMessageStream_endRequest = function _BetaMessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet2(this, _BetaMessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _BetaMessageStream_accumulateMessage = function _BetaMessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet2(this, _BetaMessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/beta/messages/messages.mjs\nvar DEPRECATED_MODELS = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nvar Messages = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches(this._client);\n }\n create(params, options) {\n var _a2, _b;\n const { betas, ...body } = params;\n if (body.model in DEPRECATED_MODELS) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages?beta=true\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n headers: {\n ...(betas == null ? void 0 : betas.toString()) != null ? { \"anthropic-beta\": betas == null ? void 0 : betas.toString() } : void 0,\n ...options == null ? void 0 : options.headers\n },\n stream: (_b = params.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return BetaMessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(params, options) {\n const { betas, ...body } = params;\n return this._client.post(\"/v1/messages/count_tokens?beta=true\", {\n body,\n ...options,\n headers: {\n \"anthropic-beta\": [...betas != null ? betas : [], \"token-counting-2024-11-01\"].toString(),\n ...options == null ? void 0 : options.headers\n }\n });\n }\n};\nMessages.Batches = Batches;\nMessages.BetaMessageBatchesPage = BetaMessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/beta/beta.mjs\nvar Beta = class extends APIResource {\n constructor() {\n super(...arguments);\n this.models = new Models(this._client);\n this.messages = new Messages(this._client);\n }\n};\nBeta.Models = Models;\nBeta.BetaModelInfosPage = BetaModelInfosPage;\nBeta.Messages = Messages;\n\n// node_modules/@anthropic-ai/sdk/resources/completions.mjs\nvar Completions = class extends APIResource {\n create(body, options) {\n var _a2, _b;\n return this._client.post(\"/v1/complete\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n};\n\n// node_modules/@anthropic-ai/sdk/resources/messages/batches.mjs\nvar Batches2 = class extends APIResource {\n /**\n * Send a batch of Message creation requests.\n *\n * The Message Batches API can be used to process multiple Messages API requests at\n * once. Once a Message Batch is created, it begins processing immediately. Batches\n * can take up to 24 hours to complete.\n */\n create(body, options) {\n return this._client.post(\"/v1/messages/batches\", { body, ...options });\n }\n /**\n * This endpoint is idempotent and can be used to poll for Message Batch\n * completion. To access the results of a Message Batch, make a request to the\n * `results_url` field in the response.\n */\n retrieve(messageBatchId, options) {\n return this._client.get(`/v1/messages/batches/${messageBatchId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/messages/batches\", MessageBatchesPage, { query, ...options });\n }\n /**\n * Delete a Message Batch.\n *\n * Message Batches can only be deleted once they've finished processing. If you'd\n * like to delete an in-progress batch, you must first cancel it.\n */\n delete(messageBatchId, options) {\n return this._client.delete(`/v1/messages/batches/${messageBatchId}`, options);\n }\n /**\n * Batches may be canceled any time before processing ends. Once cancellation is\n * initiated, the batch enters a `canceling` state, at which time the system may\n * complete any in-progress, non-interruptible requests before finalizing\n * cancellation.\n *\n * The number of canceled requests is specified in `request_counts`. To determine\n * which requests were canceled, check the individual results within the batch.\n * Note that cancellation may not result in any canceled requests if they were\n * non-interruptible.\n */\n cancel(messageBatchId, options) {\n return this._client.post(`/v1/messages/batches/${messageBatchId}/cancel`, options);\n }\n /**\n * Streams the results of a Message Batch as a `.jsonl` file.\n *\n * Each line in the file is a JSON object containing the result of a single request\n * in the Message Batch. Results are not guaranteed to be in the same order as\n * requests. Use the `custom_id` field to match results to requests.\n */\n async results(messageBatchId, options) {\n const batch = await this.retrieve(messageBatchId);\n if (!batch.results_url) {\n throw new AnthropicError(`No batch \\`results_url\\`; Has it finished processing? ${batch.processing_status} - ${batch.id}`);\n }\n return this._client.get(batch.results_url, {\n ...options,\n headers: {\n Accept: \"application/binary\",\n ...options == null ? void 0 : options.headers\n },\n __binaryResponse: true\n })._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller));\n }\n};\nvar MessageBatchesPage = class extends Page {\n};\nBatches2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/lib/MessageStream.mjs\nvar __classPrivateFieldSet3 = function(receiver, state, value, kind2, f) {\n if (kind2 === \"m\")\n throw new TypeError(\"Private method is not writable\");\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return kind2 === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;\n};\nvar __classPrivateFieldGet3 = function(receiver, state, kind2, f) {\n if (kind2 === \"a\" && !f)\n throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver))\n throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind2 === \"m\" ? f : kind2 === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar _MessageStream_instances;\nvar _MessageStream_currentMessageSnapshot;\nvar _MessageStream_connectedPromise;\nvar _MessageStream_resolveConnectedPromise;\nvar _MessageStream_rejectConnectedPromise;\nvar _MessageStream_endPromise;\nvar _MessageStream_resolveEndPromise;\nvar _MessageStream_rejectEndPromise;\nvar _MessageStream_listeners;\nvar _MessageStream_ended;\nvar _MessageStream_errored;\nvar _MessageStream_aborted;\nvar _MessageStream_catchingPromiseCreated;\nvar _MessageStream_response;\nvar _MessageStream_request_id;\nvar _MessageStream_getFinalMessage;\nvar _MessageStream_getFinalText;\nvar _MessageStream_handleError;\nvar _MessageStream_beginRequest;\nvar _MessageStream_addStreamEvent;\nvar _MessageStream_endRequest;\nvar _MessageStream_accumulateMessage;\nvar JSON_BUF_PROPERTY2 = \"__json_buf\";\nvar MessageStream = class {\n constructor() {\n _MessageStream_instances.add(this);\n this.messages = [];\n this.receivedMessages = [];\n _MessageStream_currentMessageSnapshot.set(this, void 0);\n this.controller = new AbortController();\n _MessageStream_connectedPromise.set(this, void 0);\n _MessageStream_resolveConnectedPromise.set(this, () => {\n });\n _MessageStream_rejectConnectedPromise.set(this, () => {\n });\n _MessageStream_endPromise.set(this, void 0);\n _MessageStream_resolveEndPromise.set(this, () => {\n });\n _MessageStream_rejectEndPromise.set(this, () => {\n });\n _MessageStream_listeners.set(this, {});\n _MessageStream_ended.set(this, false);\n _MessageStream_errored.set(this, false);\n _MessageStream_aborted.set(this, false);\n _MessageStream_catchingPromiseCreated.set(this, false);\n _MessageStream_response.set(this, void 0);\n _MessageStream_request_id.set(this, void 0);\n _MessageStream_handleError.set(this, (error) => {\n __classPrivateFieldSet3(this, _MessageStream_errored, true, \"f\");\n if (error instanceof Error && error.name === \"AbortError\") {\n error = new APIUserAbortError();\n }\n if (error instanceof APIUserAbortError) {\n __classPrivateFieldSet3(this, _MessageStream_aborted, true, \"f\");\n return this._emit(\"abort\", error);\n }\n if (error instanceof AnthropicError) {\n return this._emit(\"error\", error);\n }\n if (error instanceof Error) {\n const anthropicError = new AnthropicError(error.message);\n anthropicError.cause = error;\n return this._emit(\"error\", anthropicError);\n }\n return this._emit(\"error\", new AnthropicError(String(error)));\n });\n __classPrivateFieldSet3(this, _MessageStream_connectedPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveConnectedPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectConnectedPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldSet3(this, _MessageStream_endPromise, new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_resolveEndPromise, resolve, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_rejectEndPromise, reject, \"f\");\n }), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\").catch(() => {\n });\n __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\").catch(() => {\n });\n }\n get response() {\n return __classPrivateFieldGet3(this, _MessageStream_response, \"f\");\n }\n get request_id() {\n return __classPrivateFieldGet3(this, _MessageStream_request_id, \"f\");\n }\n /**\n * Returns the `MessageStream` data, the raw `Response` instance and the ID of the request,\n * returned vie the `request-id` header which is useful for debugging requests and resporting\n * issues to Anthropic.\n *\n * This is the same as the `APIPromise.withResponse()` method.\n *\n * This method will raise an error if you created the stream using `MessageStream.fromReadableStream`\n * as no `Response` is available.\n */\n async withResponse() {\n const response = await __classPrivateFieldGet3(this, _MessageStream_connectedPromise, \"f\");\n if (!response) {\n throw new Error(\"Could not resolve a `Response` object\");\n }\n return {\n data: this,\n response,\n request_id: response.headers.get(\"request-id\")\n };\n }\n /**\n * Intended for use on the frontend, consuming a stream produced with\n * `.toReadableStream()` on the backend.\n *\n * Note that messages sent to the model do not appear in `.on('message')`\n * in this context.\n */\n static fromReadableStream(stream) {\n const runner = new MessageStream();\n runner._run(() => runner._fromReadableStream(stream));\n return runner;\n }\n static createMessage(messages, params, options) {\n const runner = new MessageStream();\n for (const message of params.messages) {\n runner._addMessageParam(message);\n }\n runner._run(() => runner._createMessage(messages, { ...params, stream: true }, { ...options, headers: { ...options == null ? void 0 : options.headers, \"X-Stainless-Helper-Method\": \"stream\" } }));\n return runner;\n }\n _run(executor) {\n executor().then(() => {\n this._emitFinal();\n this._emit(\"end\");\n }, __classPrivateFieldGet3(this, _MessageStream_handleError, \"f\"));\n }\n _addMessageParam(message) {\n this.messages.push(message);\n }\n _addMessage(message, emit = true) {\n this.receivedMessages.push(message);\n if (emit) {\n this._emit(\"message\", message);\n }\n }\n async _createMessage(messages, params, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n const { response, data: stream } = await messages.create({ ...params, stream: true }, { ...options, signal: this.controller.signal }).withResponse();\n this._connected(response);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n _connected(response) {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_response, response, \"f\");\n __classPrivateFieldSet3(this, _MessageStream_request_id, response == null ? void 0 : response.headers.get(\"request-id\"), \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveConnectedPromise, \"f\").call(this, response);\n this._emit(\"connect\");\n }\n get ended() {\n return __classPrivateFieldGet3(this, _MessageStream_ended, \"f\");\n }\n get errored() {\n return __classPrivateFieldGet3(this, _MessageStream_errored, \"f\");\n }\n get aborted() {\n return __classPrivateFieldGet3(this, _MessageStream_aborted, \"f\");\n }\n abort() {\n this.controller.abort();\n }\n /**\n * Adds the listener function to the end of the listeners array for the event.\n * No checks are made to see if the listener has already been added. Multiple calls passing\n * the same combination of event and listener will result in the listener being added, and\n * called, multiple times.\n * @returns this MessageStream, so that calls can be chained\n */\n on(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener });\n return this;\n }\n /**\n * Removes the specified listener from the listener array for the event.\n * off() will remove, at most, one instance of a listener from the listener array. If any single\n * listener has been added multiple times to the listener array for the specified event, then\n * off() must be called multiple times to remove each instance.\n * @returns this MessageStream, so that calls can be chained\n */\n off(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (!listeners)\n return this;\n const index = listeners.findIndex((l) => l.listener === listener);\n if (index >= 0)\n listeners.splice(index, 1);\n return this;\n }\n /**\n * Adds a one-time listener function for the event. The next time the event is triggered,\n * this listener is removed and then invoked.\n * @returns this MessageStream, so that calls can be chained\n */\n once(event, listener) {\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] || (__classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = []);\n listeners.push({ listener, once: true });\n return this;\n }\n /**\n * This is similar to `.once()`, but returns a Promise that resolves the next time\n * the event is triggered, instead of calling a listener callback.\n * @returns a Promise that resolves the next time given event is triggered,\n * or rejects if an error is emitted. (If you request the 'error' event,\n * returns a promise that resolves with the error).\n *\n * Example:\n *\n * const message = await stream.emitted('message') // rejects if the stream errors\n */\n emitted(event) {\n return new Promise((resolve, reject) => {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n if (event !== \"error\")\n this.once(\"error\", reject);\n this.once(event, resolve);\n });\n }\n async done() {\n __classPrivateFieldSet3(this, _MessageStream_catchingPromiseCreated, true, \"f\");\n await __classPrivateFieldGet3(this, _MessageStream_endPromise, \"f\");\n }\n get currentMessage() {\n return __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n }\n /**\n * @returns a promise that resolves with the the final assistant Message response,\n * or rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalMessage() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this);\n }\n /**\n * @returns a promise that resolves with the the final assistant Message's text response, concatenated\n * together if there are more than one text blocks.\n * Rejects if an error occurred or the stream ended prematurely without producing a Message.\n */\n async finalText() {\n await this.done();\n return __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalText).call(this);\n }\n _emit(event, ...args) {\n if (__classPrivateFieldGet3(this, _MessageStream_ended, \"f\"))\n return;\n if (event === \"end\") {\n __classPrivateFieldSet3(this, _MessageStream_ended, true, \"f\");\n __classPrivateFieldGet3(this, _MessageStream_resolveEndPromise, \"f\").call(this);\n }\n const listeners = __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event];\n if (listeners) {\n __classPrivateFieldGet3(this, _MessageStream_listeners, \"f\")[event] = listeners.filter((l) => !l.once);\n listeners.forEach(({ listener }) => listener(...args));\n }\n if (event === \"abort\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n return;\n }\n if (event === \"error\") {\n const error = args[0];\n if (!__classPrivateFieldGet3(this, _MessageStream_catchingPromiseCreated, \"f\") && !(listeners == null ? void 0 : listeners.length)) {\n Promise.reject(error);\n }\n __classPrivateFieldGet3(this, _MessageStream_rejectConnectedPromise, \"f\").call(this, error);\n __classPrivateFieldGet3(this, _MessageStream_rejectEndPromise, \"f\").call(this, error);\n this._emit(\"end\");\n }\n }\n _emitFinal() {\n const finalMessage = this.receivedMessages.at(-1);\n if (finalMessage) {\n this._emit(\"finalMessage\", __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_getFinalMessage).call(this));\n }\n }\n async _fromReadableStream(readableStream, options) {\n var _a2;\n const signal = options == null ? void 0 : options.signal;\n if (signal) {\n if (signal.aborted)\n this.controller.abort();\n signal.addEventListener(\"abort\", () => this.controller.abort());\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_beginRequest).call(this);\n this._connected(null);\n const stream = Stream.fromReadableStream(readableStream, this.controller);\n for await (const event of stream) {\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_addStreamEvent).call(this, event);\n }\n if ((_a2 = stream.controller.signal) == null ? void 0 : _a2.aborted) {\n throw new APIUserAbortError();\n }\n __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_endRequest).call(this);\n }\n [(_MessageStream_currentMessageSnapshot = /* @__PURE__ */ new WeakMap(), _MessageStream_connectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectConnectedPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_endPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_resolveEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_rejectEndPromise = /* @__PURE__ */ new WeakMap(), _MessageStream_listeners = /* @__PURE__ */ new WeakMap(), _MessageStream_ended = /* @__PURE__ */ new WeakMap(), _MessageStream_errored = /* @__PURE__ */ new WeakMap(), _MessageStream_aborted = /* @__PURE__ */ new WeakMap(), _MessageStream_catchingPromiseCreated = /* @__PURE__ */ new WeakMap(), _MessageStream_response = /* @__PURE__ */ new WeakMap(), _MessageStream_request_id = /* @__PURE__ */ new WeakMap(), _MessageStream_handleError = /* @__PURE__ */ new WeakMap(), _MessageStream_instances = /* @__PURE__ */ new WeakSet(), _MessageStream_getFinalMessage = function _MessageStream_getFinalMessage2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n return this.receivedMessages.at(-1);\n }, _MessageStream_getFinalText = function _MessageStream_getFinalText2() {\n if (this.receivedMessages.length === 0) {\n throw new AnthropicError(\"stream ended without producing a Message with role=assistant\");\n }\n const textBlocks = this.receivedMessages.at(-1).content.filter((block) => block.type === \"text\").map((block) => block.text);\n if (textBlocks.length === 0) {\n throw new AnthropicError(\"stream ended without producing a content block with type=text\");\n }\n return textBlocks.join(\" \");\n }, _MessageStream_beginRequest = function _MessageStream_beginRequest2() {\n if (this.ended)\n return;\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n }, _MessageStream_addStreamEvent = function _MessageStream_addStreamEvent2(event) {\n var _a2;\n if (this.ended)\n return;\n const messageSnapshot = __classPrivateFieldGet3(this, _MessageStream_instances, \"m\", _MessageStream_accumulateMessage).call(this, event);\n this._emit(\"streamEvent\", event, messageSnapshot);\n switch (event.type) {\n case \"content_block_delta\": {\n const content = messageSnapshot.content.at(-1);\n switch (event.delta.type) {\n case \"text_delta\": {\n if (content.type === \"text\") {\n this._emit(\"text\", event.delta.text, content.text || \"\");\n }\n break;\n }\n case \"citations_delta\": {\n if (content.type === \"text\") {\n this._emit(\"citation\", event.delta.citation, (_a2 = content.citations) != null ? _a2 : []);\n }\n break;\n }\n case \"input_json_delta\": {\n if (content.type === \"tool_use\" && content.input) {\n this._emit(\"inputJson\", event.delta.partial_json, content.input);\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n break;\n }\n case \"message_stop\": {\n this._addMessageParam(messageSnapshot);\n this._addMessage(messageSnapshot, true);\n break;\n }\n case \"content_block_stop\": {\n this._emit(\"contentBlock\", messageSnapshot.content.at(-1));\n break;\n }\n case \"message_start\": {\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, messageSnapshot, \"f\");\n break;\n }\n case \"content_block_start\":\n case \"message_delta\":\n break;\n }\n }, _MessageStream_endRequest = function _MessageStream_endRequest2() {\n if (this.ended) {\n throw new AnthropicError(`stream has ended, this shouldn't happen`);\n }\n const snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (!snapshot) {\n throw new AnthropicError(`request ended without sending any chunks`);\n }\n __classPrivateFieldSet3(this, _MessageStream_currentMessageSnapshot, void 0, \"f\");\n return snapshot;\n }, _MessageStream_accumulateMessage = function _MessageStream_accumulateMessage2(event) {\n var _a2;\n let snapshot = __classPrivateFieldGet3(this, _MessageStream_currentMessageSnapshot, \"f\");\n if (event.type === \"message_start\") {\n if (snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before receiving \"message_stop\"`);\n }\n return event.message;\n }\n if (!snapshot) {\n throw new AnthropicError(`Unexpected event order, got ${event.type} before \"message_start\"`);\n }\n switch (event.type) {\n case \"message_stop\":\n return snapshot;\n case \"message_delta\":\n snapshot.stop_reason = event.delta.stop_reason;\n snapshot.stop_sequence = event.delta.stop_sequence;\n snapshot.usage.output_tokens = event.usage.output_tokens;\n return snapshot;\n case \"content_block_start\":\n snapshot.content.push(event.content_block);\n return snapshot;\n case \"content_block_delta\": {\n const snapshotContent = snapshot.content.at(event.index);\n switch (event.delta.type) {\n case \"text_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n snapshotContent.text += event.delta.text;\n }\n break;\n }\n case \"citations_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"text\") {\n (_a2 = snapshotContent.citations) != null ? _a2 : snapshotContent.citations = [];\n snapshotContent.citations.push(event.delta.citation);\n }\n break;\n }\n case \"input_json_delta\": {\n if ((snapshotContent == null ? void 0 : snapshotContent.type) === \"tool_use\") {\n let jsonBuf = snapshotContent[JSON_BUF_PROPERTY2] || \"\";\n jsonBuf += event.delta.partial_json;\n Object.defineProperty(snapshotContent, JSON_BUF_PROPERTY2, {\n value: jsonBuf,\n enumerable: false,\n writable: true\n });\n if (jsonBuf) {\n snapshotContent.input = partialParse(jsonBuf);\n }\n }\n break;\n }\n default:\n checkNever2(event.delta);\n }\n return snapshot;\n }\n case \"content_block_stop\":\n return snapshot;\n }\n }, Symbol.asyncIterator)]() {\n const pushQueue = [];\n const readQueue = [];\n let done = false;\n this.on(\"streamEvent\", (event) => {\n const reader = readQueue.shift();\n if (reader) {\n reader.resolve(event);\n } else {\n pushQueue.push(event);\n }\n });\n this.on(\"end\", () => {\n done = true;\n for (const reader of readQueue) {\n reader.resolve(void 0);\n }\n readQueue.length = 0;\n });\n this.on(\"abort\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n this.on(\"error\", (err) => {\n done = true;\n for (const reader of readQueue) {\n reader.reject(err);\n }\n readQueue.length = 0;\n });\n return {\n next: async () => {\n if (!pushQueue.length) {\n if (done) {\n return { value: void 0, done: true };\n }\n return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((chunk2) => chunk2 ? { value: chunk2, done: false } : { value: void 0, done: true });\n }\n const chunk = pushQueue.shift();\n return { value: chunk, done: false };\n },\n return: async () => {\n this.abort();\n return { value: void 0, done: true };\n }\n };\n }\n toReadableStream() {\n const stream = new Stream(this[Symbol.asyncIterator].bind(this), this.controller);\n return stream.toReadableStream();\n }\n};\nfunction checkNever2(x) {\n}\n\n// node_modules/@anthropic-ai/sdk/resources/messages/messages.mjs\nvar Messages2 = class extends APIResource {\n constructor() {\n super(...arguments);\n this.batches = new Batches2(this._client);\n }\n create(body, options) {\n var _a2, _b;\n if (body.model in DEPRECATED_MODELS2) {\n console.warn(`The model '${body.model}' is deprecated and will reach end-of-life on ${DEPRECATED_MODELS2[body.model]}\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.`);\n }\n return this._client.post(\"/v1/messages\", {\n body,\n timeout: (_a2 = this._client._options.timeout) != null ? _a2 : 6e5,\n ...options,\n stream: (_b = body.stream) != null ? _b : false\n });\n }\n /**\n * Create a Message stream\n */\n stream(body, options) {\n return MessageStream.createMessage(this, body, options);\n }\n /**\n * Count the number of tokens in a Message.\n *\n * The Token Count API can be used to count the number of tokens in a Message,\n * including tools, images, and documents, without creating it.\n */\n countTokens(body, options) {\n return this._client.post(\"/v1/messages/count_tokens\", { body, ...options });\n }\n};\nvar DEPRECATED_MODELS2 = {\n \"claude-1.3\": \"November 6th, 2024\",\n \"claude-1.3-100k\": \"November 6th, 2024\",\n \"claude-instant-1.1\": \"November 6th, 2024\",\n \"claude-instant-1.1-100k\": \"November 6th, 2024\",\n \"claude-instant-1.2\": \"November 6th, 2024\",\n \"claude-3-sonnet-20240229\": \"July 21st, 2025\",\n \"claude-2.1\": \"July 21st, 2025\",\n \"claude-2.0\": \"July 21st, 2025\"\n};\nMessages2.Batches = Batches2;\nMessages2.MessageBatchesPage = MessageBatchesPage;\n\n// node_modules/@anthropic-ai/sdk/resources/models.mjs\nvar Models2 = class extends APIResource {\n /**\n * Get a specific model.\n *\n * The Models API response can be used to determine information about a specific\n * model or resolve a model alias to a model ID.\n */\n retrieve(modelId, options) {\n return this._client.get(`/v1/models/${modelId}`, options);\n }\n list(query = {}, options) {\n if (isRequestOptions(query)) {\n return this.list({}, query);\n }\n return this._client.getAPIList(\"/v1/models\", ModelInfosPage, { query, ...options });\n }\n};\nvar ModelInfosPage = class extends Page {\n};\nModels2.ModelInfosPage = ModelInfosPage;\n\n// node_modules/@anthropic-ai/sdk/index.mjs\nvar _a;\nvar Anthropic = class extends APIClient {\n /**\n * API Client for interfacing with the Anthropic API.\n *\n * @param {string | null | undefined} [opts.apiKey=process.env['ANTHROPIC_API_KEY'] ?? null]\n * @param {string | null | undefined} [opts.authToken=process.env['ANTHROPIC_AUTH_TOKEN'] ?? null]\n * @param {string} [opts.baseURL=process.env['ANTHROPIC_BASE_URL'] ?? https://api.anthropic.com] - Override the default base URL for the API.\n * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.\n * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.\n * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation.\n * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request.\n * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API.\n * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API.\n * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers.\n */\n constructor({ baseURL = readEnv(\"ANTHROPIC_BASE_URL\"), apiKey = ((_a2) => (_a2 = readEnv(\"ANTHROPIC_API_KEY\")) != null ? _a2 : null)(), authToken = ((_b) => (_b = readEnv(\"ANTHROPIC_AUTH_TOKEN\")) != null ? _b : null)(), ...opts } = {}) {\n var _a3;\n const options = {\n apiKey,\n authToken,\n ...opts,\n baseURL: baseURL || `https://api.anthropic.com`\n };\n if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) {\n throw new AnthropicError(\"It looks like you're running in a browser-like environment.\\n\\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\\nIf you understand the risks and have appropriate mitigations in place,\\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\\n\\nnew Anthropic({ apiKey, dangerouslyAllowBrowser: true });\\n\");\n }\n super({\n baseURL: options.baseURL,\n timeout: (_a3 = options.timeout) != null ? _a3 : 6e5,\n httpAgent: options.httpAgent,\n maxRetries: options.maxRetries,\n fetch: options.fetch\n });\n this.completions = new Completions(this);\n this.messages = new Messages2(this);\n this.models = new Models2(this);\n this.beta = new Beta(this);\n this._options = options;\n this.apiKey = apiKey;\n this.authToken = authToken;\n }\n defaultQuery() {\n return this._options.defaultQuery;\n }\n defaultHeaders(opts) {\n return {\n ...super.defaultHeaders(opts),\n ...this._options.dangerouslyAllowBrowser ? { \"anthropic-dangerous-direct-browser-access\": \"true\" } : void 0,\n \"anthropic-version\": \"2023-06-01\",\n ...this._options.defaultHeaders\n };\n }\n validateHeaders(headers, customHeaders) {\n if (this.apiKey && headers[\"x-api-key\"]) {\n return;\n }\n if (customHeaders[\"x-api-key\"] === null) {\n return;\n }\n if (this.authToken && headers[\"authorization\"]) {\n return;\n }\n if (customHeaders[\"authorization\"] === null) {\n return;\n }\n throw new Error('Could not resolve authentication method. Expected either apiKey or authToken to be set. Or for one of the \"X-Api-Key\" or \"Authorization\" headers to be explicitly omitted');\n }\n authHeaders(opts) {\n const apiKeyAuth = this.apiKeyAuth(opts);\n const bearerAuth = this.bearerAuth(opts);\n if (apiKeyAuth != null && !isEmptyObj(apiKeyAuth)) {\n return apiKeyAuth;\n }\n if (bearerAuth != null && !isEmptyObj(bearerAuth)) {\n return bearerAuth;\n }\n return {};\n }\n apiKeyAuth(opts) {\n if (this.apiKey == null) {\n return {};\n }\n return { \"X-Api-Key\": this.apiKey };\n }\n bearerAuth(opts) {\n if (this.authToken == null) {\n return {};\n }\n return { Authorization: `Bearer ${this.authToken}` };\n }\n};\n_a = Anthropic;\nAnthropic.Anthropic = _a;\nAnthropic.HUMAN_PROMPT = \"\\n\\nHuman:\";\nAnthropic.AI_PROMPT = \"\\n\\nAssistant:\";\nAnthropic.DEFAULT_TIMEOUT = 6e5;\nAnthropic.AnthropicError = AnthropicError;\nAnthropic.APIError = APIError;\nAnthropic.APIConnectionError = APIConnectionError;\nAnthropic.APIConnectionTimeoutError = APIConnectionTimeoutError;\nAnthropic.APIUserAbortError = APIUserAbortError;\nAnthropic.NotFoundError = NotFoundError;\nAnthropic.ConflictError = ConflictError;\nAnthropic.RateLimitError = RateLimitError;\nAnthropic.BadRequestError = BadRequestError;\nAnthropic.AuthenticationError = AuthenticationError;\nAnthropic.InternalServerError = InternalServerError;\nAnthropic.PermissionDeniedError = PermissionDeniedError;\nAnthropic.UnprocessableEntityError = UnprocessableEntityError;\nAnthropic.toFile = toFile;\nAnthropic.fileFromPath = fileFromPath;\nAnthropic.Completions = Completions;\nAnthropic.Messages = Messages2;\nAnthropic.Models = Models2;\nAnthropic.ModelInfosPage = ModelInfosPage;\nAnthropic.Beta = Beta;\nvar { HUMAN_PROMPT, AI_PROMPT } = Anthropic;\nvar sdk_default = Anthropic;\n\n// src/llm/anthropicProvider.ts\nvar AnthropicProvider = class {\n constructor(apiKey, model) {\n this.apiKey = apiKey;\n this.model = model;\n this.client = new sdk_default({ apiKey, dangerouslyAllowBrowser: true });\n }\n async generate(input) {\n var _a2, _b, _c, _d, _e, _f;\n const userContent = [];\n if (input.pdfBase64) {\n userContent.push({\n type: \"document\",\n source: { type: \"base64\", media_type: \"application/pdf\", data: input.pdfBase64 }\n });\n }\n userContent.push({ type: \"text\", text: input.prompt });\n const response = await this.client.messages.create({\n model: this.model,\n max_tokens: (_a2 = input.maxTokens) != null ? _a2 : 4096,\n temperature: (_b = input.temperature) != null ? _b : 0.3,\n system: input.system,\n messages: [{ role: \"user\", content: userContent }]\n });\n const textBlock = response.content.find((b) => b.type === \"text\");\n const text = (textBlock == null ? void 0 : textBlock.type) === \"text\" ? textBlock.text : \"\";\n const usage = {\n inputTokens: (_d = (_c = response.usage) == null ? void 0 : _c.input_tokens) != null ? _d : 0,\n outputTokens: (_f = (_e = response.usage) == null ? void 0 : _e.output_tokens) != null ? _f : 0\n };\n return { text, usage, raw: response };\n }\n};\n\n// src/pipeline/dailyPipeline.ts\nfunction getISODate(d) {\n return d.toISOString().slice(0, 10);\n}\nfunction buildLLMProvider(settings) {\n if (settings.llm.provider === \"anthropic\") {\n return new AnthropicProvider(settings.llm.apiKey, settings.llm.model);\n }\n return new OpenAICompatibleProvider(settings.llm.baseUrl, settings.llm.apiKey, settings.llm.model);\n}\nfunction fillTemplate(template, vars) {\n let result = template;\n for (const [k, v] of Object.entries(vars)) {\n result = result.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, \"g\"), v);\n }\n return result;\n}\nfunction getActivePrompt(settings) {\n if (settings.promptLibrary && settings.activePromptId) {\n const tpl = settings.promptLibrary.find((t) => t.id === settings.activePromptId);\n if (tpl)\n return tpl.prompt;\n }\n return settings.llm.dailyPromptTemplate;\n}\nfunction escapeTableCell(s) {\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\n/g, \" \").replace(/\\r/g, \"\").trim();\n}\nfunction buildDailyMarkdown(date, settings, rankedPapers, aiDigest, activeSources, error) {\n var _a2;\n const frontmatter = [\n \"---\",\n \"type: paper-daily\",\n `date: ${date}`,\n `sources: [${activeSources.join(\", \")}]`,\n `categories: [${settings.categories.join(\", \")}]`,\n `interestKeywords: [${settings.interestKeywords.map((k) => `${k.keyword}(${k.weight})`).join(\", \")}]`,\n \"---\"\n ].join(\"\\n\");\n const header = `# Paper Daily \\u2014 ${date}`;\n const modelAttr = error ? \"\" : ` | by ${settings.llm.model} \\u8001\\u5E08 \\u{1F916}`;\n const digestSection = error ? `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09\n\n> **Error**: ${error}` : `## \\u4ECA\\u65E5\\u8981\\u70B9\\uFF08AI \\u603B\\u7ED3\\uFF09${modelAttr}\n\n${aiDigest}`;\n const tableRows = rankedPapers.map((p, i) => {\n var _a3, _b;\n const titleLink = p.links.html ? `[${escapeTableCell(p.title)}](${p.links.html})` : escapeTableCell(p.title);\n const linkParts = [];\n if (p.links.html)\n linkParts.push(`[arXiv](${p.links.html})`);\n if (p.links.hf)\n linkParts.push(`[\\u{1F917} HF](${p.links.hf})`);\n if (settings.includePdfLink && p.links.pdf)\n linkParts.push(`[PDF](${p.links.pdf})`);\n if (p.links.localPdf)\n linkParts.push(`[Local PDF](${p.links.localPdf})`);\n const score = p.llmScore != null ? `\\u2B50${p.llmScore}/10` : \"-\";\n const summary = escapeTableCell((_a3 = p.llmSummary) != null ? _a3 : \"\");\n const hits = ((_b = p.interestHits) != null ? _b : []).slice(0, 3).join(\", \") || \"-\";\n return `| ${i + 1} | ${titleLink} | ${linkParts.join(\" \")} | ${score} | ${summary} | ${hits} |`;\n });\n const allPapersTableSection = [\n \"## All Papers\",\n \"\",\n \"| # | Title | Links | Score | Summary | Hits |\",\n \"|---|-------|-------|-------|---------|------|\",\n ...tableRows.length > 0 ? tableRows : [\"| \\u2014 | _No papers_ | | | | |\"]\n ].join(\"\\n\");\n let localPdfsSection = \"\";\n if ((_a2 = settings.paperDownload) == null ? void 0 : _a2.savePdf) {\n const pdfsWithLocal = rankedPapers.filter((p) => p.links.localPdf);\n if (pdfsWithLocal.length > 0) {\n const lines = pdfsWithLocal.map(\n (p) => `- [${p.title}](${p.links.localPdf})`\n );\n localPdfsSection = `## \\u672C\\u5730 PDF / Local PDFs (${pdfsWithLocal.length} \\u7BC7)\n\n${lines.join(\"\\n\")}`;\n }\n }\n const sections = [frontmatter, \"\", header, \"\", digestSection];\n if (localPdfsSection)\n sections.push(\"\", localPdfsSection);\n sections.push(\"\", allPapersTableSection);\n return sections.join(\"\\n\");\n}\nasync function runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, options = {}) {\n var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;\n const writer = new VaultWriter(app);\n const now = new Date();\n const date = (_a2 = options.targetDate) != null ? _a2 : getISODate(now);\n const logPath = `${settings.rootFolder}/cache/runs.log`;\n const inboxPath = `${settings.rootFolder}/inbox/${date}.md`;\n const snapshotPath = `${settings.rootFolder}/papers/${date}.json`;\n const logLines = [];\n const log = (msg) => {\n const line = `[${new Date().toISOString()}] ${msg}`;\n logLines.push(line);\n console.log(`[PaperDaily] ${msg}`);\n };\n const progress = (_b = options.onProgress) != null ? _b : () => {\n };\n let totalInputTokens = 0;\n let totalOutputTokens = 0;\n const trackUsage = (label, inputTokens, outputTokens) => {\n totalInputTokens += inputTokens;\n totalOutputTokens += outputTokens;\n log(`${label} tokens: input=${inputTokens} output=${outputTokens}`);\n };\n log(`=== Daily pipeline START date=${date} ===`);\n const interestKeywords = (_c = settings.interestKeywords) != null ? _c : [];\n log(`Settings: categories=[${settings.categories.join(\",\")}] interestKeywords=${interestKeywords.length} fetchMode=${(_d = settings.fetchMode) != null ? _d : \"all\"}`);\n let papers = [];\n let hfDailyPapers = [];\n let fetchError;\n let llmDigest = \"\";\n let llmError;\n const activeSources = [];\n progress(`[1/5] \\u{1F4E1} \\u62C9\\u53D6 arXiv \\u8BBA\\u6587...`);\n let fetchUrl = \"\";\n try {\n const source = new ArxivSource();\n const windowEnd = (_e = options.windowEnd) != null ? _e : now;\n const windowStart = (_g = options.windowStart) != null ? _g : new Date(windowEnd.getTime() - ((_f = settings.timeWindowHours) != null ? _f : 72) * 3600 * 1e3);\n fetchUrl = source.buildUrl(\n { categories: settings.categories, keywords: [], maxResults: 200, sortBy: \"submittedDate\", windowStart, windowEnd },\n 200\n );\n log(`Step 1 FETCH: url=${fetchUrl}`);\n papers = await source.fetch({\n categories: settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart,\n windowEnd,\n targetDate: date\n });\n log(`Step 1 FETCH: got ${papers.length} papers`);\n if (papers.length > 0) {\n log(`Step 1 FETCH: first=\"${papers[0].title.slice(0, 80)}\" published=${papers[0].published.slice(0, 10)}`);\n activeSources.push(\"arxiv\");\n }\n } catch (err) {\n fetchError = String(err);\n log(`Step 1 FETCH ERROR: ${fetchError}`);\n await stateStore.setLastError(\"fetch\", fetchError);\n }\n if (((_h = settings.hfSource) == null ? void 0 : _h.enabled) !== false) {\n progress(`[1/5] \\u{1F917} \\u62C9\\u53D6 HuggingFace \\u8BBA\\u6587...`);\n try {\n const hfSource = new HFSource();\n const lookback = (_j = (_i = settings.hfSource) == null ? void 0 : _i.lookbackDays) != null ? _j : 3;\n let hfFetchDate = date;\n for (let d = 0; d <= lookback; d++) {\n const tryDate = d === 0 ? date : getISODate(new Date(new Date(date + \"T12:00:00Z\").getTime() - d * 864e5));\n const fetched = await hfSource.fetchForDate(tryDate);\n if (fetched.length > 0) {\n hfDailyPapers = fetched;\n hfFetchDate = tryDate;\n break;\n }\n }\n log(`Step 1b HF FETCH: got ${hfDailyPapers.length} papers (date=${hfFetchDate}${hfFetchDate !== date ? `, lookback from ${date}` : \"\"})`);\n if (hfDailyPapers.length > 0) {\n activeSources.push(\"huggingface\");\n if (options.hfTrackStore) {\n for (const p of hfDailyPapers) {\n p.hfStreak = options.hfTrackStore.track(p.id, p.title, hfFetchDate);\n }\n await options.hfTrackStore.save();\n if ((_k = settings.hfSource) == null ? void 0 : _k.dedup) {\n const before = hfDailyPapers.length;\n hfDailyPapers = hfDailyPapers.filter((p) => !options.hfTrackStore.seenBefore(p.id, hfFetchDate));\n log(`Step 1b HF DEDUP: ${before} \\u2192 ${hfDailyPapers.length} papers (removed ${before - hfDailyPapers.length} previously seen)`);\n }\n }\n const hfByBaseId = /* @__PURE__ */ new Map();\n for (const hfp of hfDailyPapers) {\n hfByBaseId.set(hfp.id, hfp);\n }\n let enrichedCount = 0;\n const arxivBaseIds = new Set(\n papers.map((p) => `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`)\n );\n for (const p of papers) {\n const baseId = `arxiv:${p.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\")}`;\n const hfMatch = hfByBaseId.get(baseId);\n if (hfMatch) {\n p.hfUpvotes = (_l = hfMatch.hfUpvotes) != null ? _l : 0;\n if (hfMatch.links.hf)\n p.links = { ...p.links, hf: hfMatch.links.hf };\n enrichedCount++;\n }\n }\n log(`Step 1b HF MERGE: enriched ${enrichedCount}/${papers.length} arXiv papers with HF upvotes`);\n const hfOnlyPapers = hfDailyPapers.filter((p) => !arxivBaseIds.has(p.id));\n if (hfOnlyPapers.length > 0) {\n papers.push(...hfOnlyPapers);\n log(`Step 1b HF MERGE: added ${hfOnlyPapers.length} HF-only papers to scoring pool`);\n }\n }\n } catch (err) {\n log(`Step 1b HF FETCH ERROR: ${String(err)} (non-fatal, continuing)`);\n }\n } else {\n log(`Step 1b HF FETCH: skipped (disabled)`);\n }\n const countBeforeDedup = papers.length;\n const dedupEnabled = ((_m = settings.dedup) != null ? _m : true) && !options.skipDedup;\n if (dedupEnabled && papers.length > 0) {\n papers = papers.filter((p) => !dedupStore.hasId(p.id));\n }\n log(`Step 2 DEDUP: before=${countBeforeDedup} after=${papers.length} (filtered=${countBeforeDedup - papers.length}${dedupEnabled ? \"\" : \", dedup disabled\"})`);\n if (((_n = settings.fetchMode) != null ? _n : \"all\") === \"interest_only\" && interestKeywords.length > 0) {\n for (const p of papers) {\n p.interestHits = computeInterestHits(p, interestKeywords);\n }\n const before = papers.length;\n papers = papers.filter((p) => {\n var _a3;\n return ((_a3 = p.interestHits) != null ? _a3 : []).length > 0;\n });\n log(`Step 2b INTEREST FILTER: ${before} \\u2192 ${papers.length} papers (removed ${before - papers.length} with no keyword hits)`);\n }\n let rankedPapers = papers.length > 0 ? rankPapers(papers, interestKeywords) : [];\n log(`Step 3 RANK: ${rankedPapers.length} papers ranked`);\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[2/5] \\u{1F50D} \\u5FEB\\u901F\\u9884\\u7B5B ${rankedPapers.length} \\u7BC7...`);\n try {\n const llm = buildLLMProvider(settings);\n const kwStr = interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \");\n const scoringCap = Math.min(rankedPapers.length, 60);\n const papersForScoring = rankedPapers.slice(0, scoringCap).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 250),\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {}\n };\n });\n const scoringMaxTokens = Math.min(scoringCap * 150 + 256, 8192);\n const scoringPrompt = `Score each paper 1\\u201310 for quality and relevance to the user's interests.\n\nUser's interest keywords (higher weight = more important): ${kwStr}\n\nScoring criteria:\n- Alignment with interest keywords and their weights\n- Technical novelty and depth\n- Practical engineering value\n- Quality of evaluation / experiments\n\nReturn ONLY a valid JSON array, no explanation, no markdown fence:\n[{\"id\":\"arxiv:...\",\"score\":8,\"reason\":\"one short phrase\",\"summary\":\"1\\u20132 sentence plain-language summary\"},...]\n\nPapers:\n${JSON.stringify(papersForScoring)}`;\n const result = await llm.generate({ prompt: scoringPrompt, temperature: 0.1, maxTokens: scoringMaxTokens });\n if (result.usage)\n trackUsage(\"Step 3b scoring\", result.usage.inputTokens, result.usage.outputTokens);\n const jsonMatch = result.text.match(/\\[[\\s\\S]*\\]/);\n if (jsonMatch) {\n const scores = JSON.parse(jsonMatch[0]);\n const normalizeId = (id) => id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\").toLowerCase().trim();\n const scoreMap = new Map(scores.map((s) => [normalizeId(s.id), s]));\n let matched = 0;\n for (const paper of rankedPapers) {\n const s = scoreMap.get(normalizeId(paper.id));\n if (s) {\n paper.llmScore = s.score;\n paper.llmScoreReason = s.reason;\n if (s.summary)\n paper.llmSummary = s.summary;\n matched++;\n }\n }\n rankedPapers.sort((a, b) => {\n var _a3, _b2;\n return ((_a3 = b.llmScore) != null ? _a3 : -1) - ((_b2 = a.llmScore) != null ? _b2 : -1);\n });\n log(`Step 3b LLM SCORE: scored ${matched}/${rankedPapers.length} papers (LLM returned ${scores.length}), re-ranked`);\n if (matched === 0) {\n log(`Step 3b LLM SCORE WARNING: 0 matched \\u2014 ID format mismatch? Sample LLM id=\"${(_o = scores[0]) == null ? void 0 : _o.id}\" vs paper id=\"${(_p = rankedPapers[0]) == null ? void 0 : _p.id}\"`);\n }\n } else {\n log(`Step 3b LLM SCORE: could not parse JSON from response (response length=${result.text.length}, likely truncated)`);\n }\n } catch (err) {\n log(`Step 3b LLM SCORE ERROR: ${String(err)} (non-fatal, using keyword ranking)`);\n }\n } else {\n log(`Step 3b LLM SCORE: skipped (${rankedPapers.length === 0 ? \"0 papers\" : \"no API key\"})`);\n }\n if (rankedPapers.length > 0) {\n await downloadPapersForDay(app, rankedPapers, settings, log, date);\n }\n let fulltextSection = \"\";\n if (((_q = settings.deepRead) == null ? void 0 : _q.enabled) && rankedPapers.length > 0 && settings.llm.apiKey) {\n const topN = Math.min((_r = settings.deepRead.topN) != null ? _r : 5, rankedPapers.length);\n const maxTokens = (_s = settings.deepRead.deepReadMaxTokens) != null ? _s : 1024;\n const drPrompt = (_t = settings.deepRead.deepReadPromptTemplate) != null ? _t : DEFAULT_DEEP_READ_PROMPT;\n const langStr = settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\";\n progress(`[3/5] \\u{1F4D6} Deep Read \\u2014 ${topN} \\u7BC7\\u7CBE\\u8BFB\\u4E2D...`);\n const llm = buildLLMProvider(settings);\n const analysisResults = [];\n for (let i = 0; i < topN; i++) {\n const paper = rankedPapers[i];\n const baseId = paper.id.replace(/^arxiv:/i, \"\").replace(/v\\d+$/i, \"\");\n const htmlUrl = `https://arxiv.org/html/${baseId}`;\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: ${baseId} \\u2192 ${htmlUrl}`);\n const paperPrompt = fillTemplate(drPrompt, {\n title: paper.title,\n authors: ((_u = paper.authors) != null ? _u : []).slice(0, 5).join(\", \") || \"Unknown\",\n interest_hits: ((_v = paper.interestHits) != null ? _v : []).join(\", \") || \"none\",\n abstract: paper.abstract,\n fulltext: htmlUrl,\n language: langStr\n });\n try {\n const result = await llm.generate({ prompt: paperPrompt, temperature: 0.2, maxTokens });\n if (result.usage)\n trackUsage(`Step 3f deepread [${i + 1}]`, result.usage.inputTokens, result.usage.outputTokens);\n paper.deepReadAnalysis = result.text.trim();\n analysisResults.push(`### [${i + 1}] ${paper.title}\n\n${paper.deepReadAnalysis}`);\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: done (${result.text.length} chars)`);\n } catch (err) {\n log(`Step 3f DEEPREAD [${i + 1}/${topN}]: LLM error: ${String(err)} \\u2014 skipping`);\n }\n }\n if (analysisResults.length > 0) {\n fulltextSection = [\n \"\",\n `## Deep Read Analysis (top ${analysisResults.length} papers)`,\n `> Per-paper LLM analysis \\u2014 model reads full paper from arxiv.org/html directly.`,\n \"\",\n analysisResults.join(\"\\n\\n---\\n\\n\")\n ].join(\"\\n\");\n }\n log(`Step 3f DEEPREAD: ${analysisResults.length}/${topN} papers analysed`);\n } else {\n log(`Step 3f DEEPREAD: skipped (enabled=${(_x = (_w = settings.deepRead) == null ? void 0 : _w.enabled) != null ? _x : false})`);\n }\n if (rankedPapers.length > 0 && settings.llm.apiKey) {\n progress(`[4/5] \\u{1F4DD} \\u6B63\\u5728\\u751F\\u6210\\u65E5\\u62A5...`);\n log(`Step 4 LLM: provider=${settings.llm.provider} model=${settings.llm.model}`);\n try {\n const llm = buildLLMProvider(settings);\n const topK = Math.min(rankedPapers.length, 10);\n const topPapersForLLM = rankedPapers.slice(0, topK).map((p) => {\n var _a3;\n return {\n id: p.id,\n title: p.title,\n abstract: p.abstract.slice(0, 500),\n categories: p.categories,\n interestHits: (_a3 = p.interestHits) != null ? _a3 : [],\n ...p.hfUpvotes ? { hfUpvotes: p.hfUpvotes } : {},\n source: p.source,\n published: p.published,\n updated: p.updated,\n links: p.links\n };\n });\n const hfForLLM = hfDailyPapers.slice(0, 15).map((p) => {\n var _a3;\n return {\n title: p.title,\n hfUpvotes: (_a3 = p.hfUpvotes) != null ? _a3 : 0,\n ...p.hfStreak && p.hfStreak > 1 ? { streakDays: p.hfStreak } : {}\n };\n });\n const localPdfEntries = rankedPapers.filter((p) => p.links.localPdf).map((p) => `- [${p.title}](${p.links.localPdf})`);\n const localPdfsSection = localPdfEntries.length > 0 ? `## Local PDFs (${date})\n${localPdfEntries.join(\"\\n\")}` : \"\";\n const prompt2 = fillTemplate(getActivePrompt(settings), {\n date,\n papers_json: JSON.stringify(topPapersForLLM, null, 2),\n hf_papers_json: JSON.stringify(hfForLLM, null, 2),\n fulltext_section: fulltextSection,\n local_pdfs: localPdfsSection,\n interest_keywords: interestKeywords.map((k) => `${k.keyword}(weight:${k.weight})`).join(\", \"),\n language: settings.language === \"zh\" ? \"Chinese (\\u4E2D\\u6587)\" : \"English\"\n });\n const result = await llm.generate({ prompt: prompt2, temperature: settings.llm.temperature, maxTokens: settings.llm.maxTokens });\n llmDigest = result.text;\n if (result.usage)\n trackUsage(\"Step 4 digest\", result.usage.inputTokens, result.usage.outputTokens);\n log(`Step 4 LLM: success, response length=${llmDigest.length} chars`);\n } catch (err) {\n llmError = String(err);\n log(`Step 4 LLM ERROR: ${llmError}`);\n await stateStore.setLastError(\"llm\", llmError);\n }\n } else if (!settings.llm.apiKey) {\n llmError = \"LLM API key not configured\";\n log(`Step 4 LLM: skipped (no API key)`);\n } else {\n log(`Step 4 LLM: skipped (0 papers)`);\n }\n const errorMsg = fetchError ? `Fetch failed: ${fetchError}${llmError ? `\n\nLLM failed: ${llmError}` : \"\"}` : llmError ? `LLM failed: ${llmError}` : void 0;\n progress(`[5/5] \\u{1F4BE} \\u5199\\u5165\\u6587\\u4EF6...`);\n try {\n const markdown = buildDailyMarkdown(date, settings, rankedPapers, llmDigest, activeSources, errorMsg);\n await writer.writeNote(inboxPath, markdown);\n log(`Step 5 WRITE: markdown written to ${inboxPath}`);\n } catch (err) {\n log(`Step 5 WRITE ERROR: ${String(err)}`);\n await stateStore.setLastError(\"write\", String(err));\n throw err;\n }\n await snapshotStore.writeSnapshot(date, rankedPapers, fetchError);\n log(`Step 6 SNAPSHOT: written to ${snapshotPath} (${rankedPapers.length} papers)`);\n if (dedupEnabled && rankedPapers.length > 0) {\n await dedupStore.markSeenBatch(rankedPapers.map((p) => p.id), date);\n log(`Step 7 DEDUP: marked ${rankedPapers.length} IDs as seen`);\n }\n if (!options.targetDate) {\n await stateStore.setLastDailyRun(now.toISOString());\n }\n log(`=== Daily pipeline END date=${date} papers=${rankedPapers.length} ===`);\n const tokenSummary = totalInputTokens > 0 ? ` | tokens: ${totalInputTokens.toLocaleString()}\\u2192${totalOutputTokens.toLocaleString()}` : \"\";\n progress(`\\u2705 \\u5B8C\\u6210\\uFF01${rankedPapers.length} \\u7BC7\\u8BBA\\u6587${tokenSummary}`);\n await writer.appendToNote(logPath, logLines.join(\"\\n\") + \"\\n\");\n}\n\n// src/pipeline/backfillPipeline.ts\nfunction parseDateYMD(str) {\n const [y, m, d] = str.split(\"-\").map(Number);\n return new Date(y, m - 1, d);\n}\nfunction addDays(d, n) {\n const copy = new Date(d);\n copy.setDate(copy.getDate() + n);\n return copy;\n}\nfunction toDateStr(d) {\n return d.toISOString().slice(0, 10);\n}\nasync function runBackfillPipeline(app, settings, stateStore, dedupStore, snapshotStore, options) {\n const start = parseDateYMD(options.startDate);\n const end = parseDateYMD(options.endDate);\n const diffMs = end.getTime() - start.getTime();\n const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24)) + 1;\n if (diffDays < 1) {\n throw new Error(`Invalid date range: startDate must be <= endDate`);\n }\n if (diffDays > settings.backfillMaxDays) {\n throw new Error(`Backfill range (${diffDays} days) exceeds backfillMaxDays (${settings.backfillMaxDays})`);\n }\n const dates = [];\n let current = new Date(start);\n while (current <= end) {\n dates.push(toDateStr(current));\n current = addDays(current, 1);\n }\n const processed = [];\n const errors = {};\n for (let i = 0; i < dates.length; i++) {\n const date = dates[i];\n if (options.onProgress) {\n options.onProgress(date, i + 1, dates.length);\n }\n try {\n const dayStart = new Date(`${date}T00:00:00Z`);\n const dayEnd = new Date(`${date}T23:59:59Z`);\n await runDailyPipeline(app, settings, stateStore, dedupStore, snapshotStore, {\n targetDate: date,\n windowStart: dayStart,\n windowEnd: dayEnd,\n skipDedup: false\n });\n processed.push(date);\n } catch (err) {\n errors[date] = String(err);\n }\n }\n return { processed, errors };\n}\n\n// src/scheduler/scheduler.ts\nfunction parseTime(hhmm) {\n const [h, m] = hhmm.split(\":\").map(Number);\n return { hour: h != null ? h : 8, minute: m != null ? m : 0 };\n}\nfunction isSameDay(a, b) {\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n}\nvar Scheduler = class {\n constructor(getSettings, stateStore, callbacks) {\n this.getSettings = getSettings;\n this.stateStore = stateStore;\n this.callbacks = callbacks;\n this.intervalId = null;\n this.running = false;\n }\n start() {\n if (this.intervalId !== null)\n return;\n this.intervalId = window.setInterval(() => this.tick(), 60 * 1e3);\n }\n stop() {\n if (this.intervalId !== null) {\n window.clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n async tick() {\n if (this.running)\n return;\n this.running = true;\n try {\n await this.checkAndRun();\n } finally {\n this.running = false;\n }\n }\n async checkAndRun() {\n const now = new Date();\n const settings = this.getSettings();\n const state = this.stateStore.get();\n const dailyTime = parseTime(settings.schedule.dailyTime);\n const scheduledToday = new Date(now);\n scheduledToday.setHours(dailyTime.hour, dailyTime.minute, 0, 0);\n if (now >= scheduledToday) {\n const lastRun = state.lastDailyRun ? new Date(state.lastDailyRun) : null;\n const alreadyRanToday = lastRun && isSameDay(now, lastRun);\n const today = now.toISOString().slice(0, 10);\n if (!alreadyRanToday || !await this.callbacks.todayFileExists(today)) {\n await this.callbacks.onDaily();\n }\n }\n }\n};\n\n// src/main.ts\nvar PaperDailyPlugin = class extends import_obsidian7.Plugin {\n async onload() {\n await this.loadSettings();\n await this.initStorage();\n this.initScheduler();\n this.registerCommands();\n this.addSettingTab(new PaperDailySettingTab(this.app, this));\n this.app.workspace.onLayoutReady(() => {\n void this.runTodayIfMissing();\n });\n console.log(\"Paper Daily loaded.\");\n }\n onunload() {\n this.scheduler.stop();\n console.log(\"Paper Daily unloaded.\");\n }\n async loadSettings() {\n this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());\n this.settings.llm = Object.assign({}, DEFAULT_SETTINGS.llm, this.settings.llm);\n this.settings.schedule = Object.assign({}, DEFAULT_SETTINGS.schedule, this.settings.schedule);\n this.settings.hfSource = Object.assign({}, DEFAULT_SETTINGS.hfSource, this.settings.hfSource);\n this.settings.rssSource = Object.assign({}, DEFAULT_SETTINGS.rssSource, this.settings.rssSource);\n this.settings.paperDownload = Object.assign({}, DEFAULT_SETTINGS.paperDownload, this.settings.paperDownload);\n if (Array.isArray(this.settings.interestKeywords) && this.settings.interestKeywords.length > 0 && typeof this.settings.interestKeywords[0] === \"string\") {\n this.settings.interestKeywords = this.settings.interestKeywords.map((kw) => ({ keyword: kw, weight: 1 }));\n }\n }\n async saveSettings() {\n await this.saveData(this.settings);\n }\n async initStorage() {\n const writer = new VaultWriter(this.app);\n this.stateStore = new StateStore(writer, this.settings.rootFolder);\n this.dedupStore = new DedupStore(writer, this.settings.rootFolder);\n this.snapshotStore = new SnapshotStore(writer, this.settings.rootFolder);\n this.hfTrackStore = new HFTrackStore(writer, this.settings.rootFolder);\n await this.stateStore.load();\n await this.dedupStore.load();\n await this.hfTrackStore.load();\n const root = this.settings.rootFolder;\n for (const sub of [\"inbox\", \"papers\", \"cache\"]) {\n await writer.ensureFolder(`${root}/${sub}`);\n }\n }\n initScheduler() {\n this.scheduler = new Scheduler(\n () => this.settings,\n this.stateStore,\n {\n onDaily: () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u5B9A\\u65F6\\u4EFB\\u52A1\\u542F\\u52A8\\u4E2D...\", 0);\n return this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`)).then(() => {\n setTimeout(() => notice.hide(), 4e3);\n }).catch((err) => {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n });\n },\n todayFileExists: (date) => this.todayFileExists(date)\n }\n );\n this.scheduler.start();\n }\n registerCommands() {\n this.addCommand({\n id: \"run-daily-now\",\n name: \"Run daily fetch & summarize now\",\n callback: async () => {\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u542F\\u52A8\\u4E2D...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n });\n this.addCommand({\n id: \"backfill\",\n name: \"Backfill daily summaries for date range\",\n callback: () => {\n new BackfillModal(this.app, this).open();\n }\n });\n this.addCommand({\n id: \"rebuild-index\",\n name: \"Rebuild index from local cache\",\n callback: async () => {\n new import_obsidian7.Notice(\"Paper Daily: Rebuilding dedup index...\");\n try {\n await this.dedupStore.load();\n new import_obsidian7.Notice(\"Paper Daily: Index rebuilt.\");\n } catch (err) {\n new import_obsidian7.Notice(`Paper Daily Error: ${String(err)}`);\n }\n }\n });\n this.addCommand({\n id: \"open-settings\",\n name: \"Open settings\",\n callback: () => {\n var _a2;\n (_a2 = this.app.setting) == null ? void 0 : _a2.openTabById(\"paper-daily\");\n }\n });\n }\n async runDaily(onProgress) {\n await runDailyPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n { hfTrackStore: this.hfTrackStore, onProgress }\n );\n }\n todayFileExists(date) {\n const writer = new VaultWriter(this.app);\n return writer.fileExists(`${this.settings.rootFolder}/inbox/${date}.md`);\n }\n /** Called once on startup: silently generate today's file if it is missing. */\n async runTodayIfMissing() {\n const today = new Date().toISOString().slice(0, 10);\n if (await this.todayFileExists(today))\n return;\n const notice = new import_obsidian7.Notice(\"Paper Daily: \\u4ECA\\u65E5\\u6587\\u6863\\u7F3A\\u5931\\uFF0C\\u6B63\\u5728\\u751F\\u6210...\", 0);\n try {\n await this.runDaily((msg) => notice.setMessage(`Paper Daily: ${msg}`));\n setTimeout(() => notice.hide(), 4e3);\n } catch (err) {\n notice.setMessage(`Paper Daily \\u9519\\u8BEF: ${String(err)}`);\n setTimeout(() => notice.hide(), 6e3);\n }\n }\n async clearDedup() {\n await this.dedupStore.clear();\n }\n async runBackfill(startDate, endDate, onProgress) {\n const result = await runBackfillPipeline(\n this.app,\n this.settings,\n this.stateStore,\n this.dedupStore,\n this.snapshotStore,\n {\n startDate,\n endDate,\n onProgress: (date, index, total) => {\n onProgress(`Processing ${date} (${index}/${total})...`);\n }\n }\n );\n const errCount = Object.keys(result.errors).length;\n if (errCount > 0) {\n onProgress(`Done. ${result.processed.length} succeeded, ${errCount} failed: ${Object.keys(result.errors).join(\", \")}`);\n } else {\n onProgress(`Done. ${result.processed.length} days processed.`);\n }\n }\n async testFetch() {\n var _a2, _b;\n const source = new ArxivSource();\n const now = new Date();\n const params = {\n categories: this.settings.categories,\n keywords: [],\n maxResults: 200,\n sortBy: \"submittedDate\",\n windowStart: new Date(now.getTime() - 72 * 3600 * 1e3),\n windowEnd: now\n };\n const url = source.buildUrl(params, 200);\n try {\n const papers = await source.fetch(params);\n return {\n url,\n total: papers.length,\n firstTitle: (_b = (_a2 = papers[0]) == null ? void 0 : _a2.title) != null ? _b : \"(none)\"\n };\n } catch (err) {\n return { url, total: 0, firstTitle: \"\", error: String(err) };\n }\n }\n};\nvar BackfillModal = class extends import_obsidian7.Modal {\n constructor(app, plugin) {\n super(app);\n this.startDate = \"\";\n this.endDate = \"\";\n this.plugin = plugin;\n }\n onOpen() {\n const { contentEl } = this;\n contentEl.empty();\n contentEl.createEl(\"h2\", { text: \"Backfill Daily Summaries\" });\n new import_obsidian7.Setting(contentEl).setName(\"Start Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-01\").onChange((v) => {\n this.startDate = v;\n }));\n new import_obsidian7.Setting(contentEl).setName(\"End Date\").setDesc(\"YYYY-MM-DD\").addText((text) => text.setPlaceholder(\"2026-02-28\").onChange((v) => {\n this.endDate = v;\n }));\n this.statusEl = contentEl.createEl(\"p\", { text: \"\", cls: \"paper-daily-backfill-status\" });\n new import_obsidian7.Setting(contentEl).addButton((btn) => btn.setButtonText(\"Run Backfill\").setCta().onClick(async () => {\n if (!this.startDate || !this.endDate) {\n this.statusEl.setText(\"Please enter both start and end dates.\");\n return;\n }\n this.statusEl.setText(\"Starting backfill...\");\n try {\n await this.plugin.runBackfill(\n this.startDate,\n this.endDate,\n (msg) => {\n this.statusEl.setText(msg);\n }\n );\n } catch (err) {\n this.statusEl.setText(`Error: ${String(err)}`);\n }\n })).addButton((btn) => btn.setButtonText(\"Close\").onClick(() => this.close()));\n }\n onClose() {\n this.contentEl.empty();\n }\n};\n"}}}} |